2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program 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
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "PyrKernel.h"
24 #include "PyrObjectProto.h"
25 #include "PyrSymbol.h"
26 #include "InitAlloc.h"
33 double pauseBeginTime
= 0.;
34 double totalPauseTime
= 0.;
35 double maxPauseTime
= 0.;
36 double minPauseTime
= 1e9
;
38 int numPausesGreaterThanOneMillisecond
= 0;
39 int maxPauseStackScans
= 0;
40 int maxPauseFlips
= 0;
41 int maxPauseScans
= 0;
42 int maxPausePartialScans
= 0;
43 int maxPauseNumToScan
= 0;
44 int maxPauseSlotsScanned
= 0;
45 int checkStackScans
= 0;
47 int checkNumToScan
= 0;
49 int checkPartialScans
= 0;
50 int checkSlotsScanned
= 0;
54 inline void PyrGC::beginPause()
56 checkStackScans
= mStackScans
;
59 checkNumToScan
= mNumToScan
;
60 checkPartialScans
= mNumPartialScans
;
61 checkSlotsScanned
= mSlotsScanned
;
62 pauseBeginTime
= elapsedTime();
65 inline void PyrGC::endPause()
67 double pauseTime
= elapsedTime() - pauseBeginTime
;
68 if (pauseTime
> 0.001) numPausesGreaterThanOneMillisecond
++;
69 if (pauseTime
> maxPauseTime
) {
70 maxPauseTime
= pauseTime
;
71 maxPauseStackScans
= mStackScans
- checkStackScans
;
72 maxPauseFlips
= mFlips
- checkFlips
;
73 maxPauseScans
= mScans
- checkScans
;
74 maxPauseNumToScan
= checkNumToScan
;
75 maxPausePartialScans
= mNumPartialScans
- checkPartialScans
;
76 maxPauseSlotsScanned
= mSlotsScanned
- checkSlotsScanned
;
78 if (pauseTime
< minPauseTime
) minPauseTime
= pauseTime
;
79 totalPauseTime
+= pauseTime
;
83 void PyrGC::reportPause()
85 post("pauses %d\n", pauseCount
);
86 post("total pause time %g\n", totalPauseTime
);
87 post("num pauses > 1 ms %d\n", numPausesGreaterThanOneMillisecond
);
88 post("avg pause time %g\n", totalPauseTime
/ pauseCount
);
89 post("min pause time %g\n", minPauseTime
);
90 post("max pause time %g\n", maxPauseTime
);
91 post("max pause scans %d\n", maxPauseScans
);
92 post("max pause partial obj scans %d\n", maxPausePartialScans
);
93 post("max pause num to scan %d\n", maxPauseNumToScan
);
94 post("max pause flips %d\n", maxPauseFlips
);
95 post("max pause stack scans %d\n", maxPauseStackScans
);
96 post("max pause slots scanned %d\n", maxPauseSlotsScanned
);
103 numPausesGreaterThanOneMillisecond
= 0;
108 #define BEGINPAUSE beginPause();
109 #define ENDPAUSE endPause();
110 #define REPORTPAUSE reportPause();
124 black gray white free sweep
127 clear list of new nonlocal reached objects.
128 when a non local object is reached, mark it, and put it on the list if not retained.
130 send any new retained objects to other system
131 send any no longer reatined objects to the other system.
133 enqueue finalization messages
134 finalize: call finalize method, move from sweep area to free area
135 list of nonlocal objects.
136 list of nonlocal reached objects.
139 void fatalerror(const char*str
);
140 void fatalerror(const char*str
)
144 throw std::runtime_error(str
);
148 inline int ScanSize(PyrObjectHdr
*obj
) { return obj
->obj_format
<= obj_slot
? obj
->size
: 0; }
150 HOT
void PyrGC::ScanSlots(PyrSlot
*inSlots
, long inNumToScan
)
152 if (inNumToScan
== 0)
155 unsigned char whiteColor
= mWhiteColor
;
156 unsigned char greyColor
= mGreyColor
;
158 mSlotsScanned
+= inNumToScan
;
160 int foundGreyObjects
= 0;
161 PyrObjectHdr
* grey
= &mGrey
;
162 PyrObjectHdr
* greyNext
= grey
->next
;
164 PyrSlot
*slot
= inSlots
;
165 PyrSlot
*endslot
= inSlots
+ inNumToScan
;
168 PyrObject
*obj
= slotRawObject(slot
);
169 if (obj
->gc_color
== whiteColor
) {
170 /* used to be ToGrey2(obj), but rearranged for slightly better performance
172 * move obj from white to grey */
174 PyrObjectHdr
* objPrev
= obj
->prev
;
175 PyrObjectHdr
* objNext
= obj
->next
;
177 /* link in grey set */
178 greyNext
->prev
= obj
;
181 obj
->next
= greyNext
;
184 // remove from old set
185 objNext
->prev
= objPrev
;
186 objPrev
->next
= objNext
;
188 obj
->gc_color
= greyColor
;
193 } while (slot
!= endslot
);
194 mNumGrey
+= foundGreyObjects
;
197 void GCSet::Init(int inGCSet
)
199 mBlack
.classptr
= NULL
;
200 mBlack
.obj_sizeclass
= inGCSet
;
202 mBlack
.gc_color
= obj_gcmarker
;
204 mWhite
.classptr
= NULL
;
205 mWhite
.obj_sizeclass
= inGCSet
;
207 mWhite
.gc_color
= obj_gcmarker
;
211 mBlack
.next
= &mWhite
;
212 mWhite
.next
= &mBlack
;
214 mBlack
.prev
= &mWhite
;
215 mWhite
.prev
= &mBlack
;
219 void GCSet::MajorFlip()
221 // move all white items to beginning of free list
223 if (!PyrGC::IsMarker(mBlack
.next
)) {
224 // move all black items to white list
225 mWhite
.next
= mBlack
.next
;
226 mFree
->prev
= mWhite
.prev
;
227 mBlack
.next
->prev
= &mWhite
;
228 mWhite
.prev
->next
= mFree
;
231 mBlack
.next
= &mWhite
;
232 mWhite
.prev
= &mBlack
;
236 void GCSet::MinorFlip()
238 // move all white items to beginning of free list
242 PyrProcess
* newPyrProcess(VMGlobals
*g
, PyrClass
*procclassobj
);
244 PyrGC::PyrGC(VMGlobals
*g
, AllocPool
*inPool
, PyrClass
*mainProcessClass
, long poolSize
)
257 mNumPartialScans
= 0;
268 mPartialScanObj
= NULL
;
269 mPartialScanSlot
= 0;
270 mUncollectedAllocations
= 0;
272 mGrey
.classptr
= NULL
;
273 mGrey
.obj_sizeclass
= 0;
275 mGrey
.gc_color
= obj_gcmarker
;
282 mNewPool
.Init(mPool
, poolSize
, poolSize
, 9000);
284 // initialize treadmills
285 for (int i
=0; i
<kNumGCSets
; ++i
) {
288 g
->process
= NULL
; // initPyrThread checks to see if process has been started
289 mProcess
= newPyrProcess(g
, mainProcessClass
);
291 mStack
= slotRawObject(&slotRawThread(&mProcess
->mainThread
)->stack
);
293 SetNil(&slotRawThread(&mProcess
->mainThread
)->stack
);
297 g
->sp
= mStack
->slots
- 1;
298 g
->process
= mProcess
;
302 //assert(SanityCheck());
306 PyrObject
*PyrGC::NewPermanent(size_t inNumBytes
, long inFlags
, long inFormat
)
309 int32 alignedSize
= (inNumBytes
+ kAlignMask
) & ~kAlignMask
; // 16 byte align
310 int32 numSlots
= alignedSize
/ sizeof(PyrSlot
);
311 numSlots
= numSlots
< 1 ? 1 : numSlots
;
312 int32 sizeclass
= LOG2CEIL(numSlots
);
313 sizeclass
= sc_min(sizeclass
, kNumGCSizeClasses
-1);
315 int32 allocSize
= sizeof(PyrObjectHdr
) + (sizeof(PyrSlot
) << sizeclass
);
317 // allocate permanent objects
318 PyrObject
* obj
= (PyrObject
*)pyr_pool_runtime
->Alloc(allocSize
);
320 obj
->gc_color
= obj_permanent
;
321 obj
->next
= obj
->prev
= NULL
;
322 obj
->obj_sizeclass
= sizeclass
;
323 obj
->obj_format
= inFormat
;
324 obj
->obj_flags
= inFlags
;
326 obj
->classptr
= class_object
;
330 void PyrGC::BecomePermanent(PyrObject
*inObject
)
333 if (IsGrey(inObject
)) mNumGrey
--;
335 inObject
->gc_color
= obj_permanent
;
336 inObject
->obj_flags
|= obj_immutable
;
337 inObject
->next
= inObject
->prev
= inObject
;
340 void PyrGC::BecomeImmutable(PyrObject
*inObject
)
342 inObject
->obj_flags
|= obj_immutable
;
345 void DumpBackTrace(VMGlobals
*g
);
347 HOT PyrObject
*PyrGC::New(size_t inNumBytes
, long inFlags
, long inFormat
, bool inCollect
)
349 PyrObject
*obj
= NULL
;
351 if (inFlags
& obj_permanent
) {
352 return NewPermanent(inNumBytes
, inFlags
, inFormat
);
355 #ifdef GC_SANITYCHECK
361 int32 alignedSize
= (inNumBytes
+ kAlignMask
) & ~kAlignMask
; // 16 byte align
362 int32 numSlots
= alignedSize
/ sizeof(PyrSlot
);
363 numSlots
= numSlots
< 1 ? 1 : numSlots
;
364 int32 sizeclass
= LOG2CEIL(numSlots
);
365 sizeclass
= sc_min(sizeclass
, kNumGCSizeClasses
-1);
367 int32 credit
= 1L << sizeclass
;
368 mAllocTotal
+= credit
;
371 mNumToScan
+= credit
;
372 obj
= Allocate(inNumBytes
, sizeclass
, inCollect
);
374 obj
->obj_format
= inFormat
;
375 obj
->obj_flags
= inFlags
& 255;
377 obj
->classptr
= class_object
;
378 obj
->gc_color
= mWhiteColor
;
380 #ifdef GC_SANITYCHECK
388 HOT PyrObject
*PyrGC::NewFrame(size_t inNumBytes
, long inFlags
, long inFormat
, bool inAccount
)
390 PyrObject
*obj
= NULL
;
392 #ifdef GC_SANITYCHECK
398 int32 alignedSize
= (inNumBytes
+ kAlignMask
) & ~kAlignMask
; // 16 byte align
399 int32 numSlots
= alignedSize
/ sizeof(PyrSlot
);
400 numSlots
= numSlots
< 1 ? 1 : numSlots
;
401 int32 sizeclass
= LOG2CEIL(numSlots
);
402 sizeclass
= sc_min(sizeclass
, kNumGCSizeClasses
-1);
404 int32 credit
= 1L << sizeclass
;
405 mAllocTotal
+= credit
;
407 mNumToScan
+= credit
;
409 obj
= Allocate(inNumBytes
, sizeclass
, inAccount
);
411 obj
->obj_format
= inFormat
;
412 obj
->obj_flags
= inFlags
;
414 obj
->classptr
= class_frame
;
415 obj
->gc_color
= mWhiteColor
;
417 #ifdef GC_SANITYCHECK
423 PyrObject
*PyrGC::NewFinalizer(ObjFuncPtr finalizeFunc
, PyrObject
*inObject
, bool inCollect
)
425 PyrObject
*obj
= NULL
;
427 #ifdef GC_SANITYCHECK
435 int32 credit
= 1L << sizeclass
;
436 mNumToScan
+= credit
;
437 mAllocTotal
+= credit
;
440 if (inCollect
&& mNumToScan
>= kScanThreshold
) {
444 GCSet
*gcs
= mSets
+ kFinalizerSet
;
446 obj
= (PyrObject
*)gcs
->mFree
;
447 if (!IsMarker(obj
)) {
449 gcs
->mFree
= obj
->next
;
451 if (sizeclass
> kMaxPoolSet
) {
453 int32 allocSize
= sizeof(PyrObjectHdr
) + (sizeof(PyrSlot
) << sizeclass
);
454 obj
= (PyrObject
*)mPool
->Alloc(allocSize
);
456 int32 allocSize
= sizeof(PyrObjectHdr
) + (sizeof(PyrSlot
) << sizeclass
);
457 obj
= (PyrObject
*)mNewPool
.Alloc(allocSize
);
460 post("Finalizer alloc failed.\n");
463 DLInsertAfter(&gcs
->mWhite
, obj
);
467 obj
->obj_sizeclass
= sizeclass
;
468 obj
->obj_format
= obj_slot
;
471 obj
->classptr
= class_finalizer
;
472 obj
->gc_color
= mWhiteColor
;
474 SetPtr(obj
->slots
+0, (void*)finalizeFunc
);
475 SetObject(obj
->slots
+1, inObject
);
477 #ifdef GC_SANITYCHECK
484 void PyrGC::SweepBigObjects()
486 if (!mCanSweep
) return;
488 for (int i
=kMaxPoolSet
+1; i
<kNumGCSizeClasses
; ++i
) {
489 GCSet
*gcs
= mSets
+ i
;
490 PyrObjectHdr
*obj
= gcs
->mFree
;
492 if (!IsMarker(obj
)) {
493 // unlink chain of free objects
494 gcs
->mFree
= obj
->prev
->next
= &gcs
->mBlack
;
495 gcs
->mBlack
.prev
= obj
->prev
;
498 PyrObjectHdr
*nextobj
= obj
->next
;
499 void* ptr
= (void*)obj
;
502 } while (!IsMarker(obj
));
508 void PyrGC::CompletePartialScan(PyrObject
*obj
)
510 if (mPartialScanObj
== obj
) {
511 int32 remain
= obj
->size
- mPartialScanSlot
;
512 ScanSlots(mPartialScanObj
->slots
+ mPartialScanSlot
, remain
);
516 HOT
void PyrGC::DoPartialScan(int32 inObjSize
)
518 int32 remain
= inObjSize
- mPartialScanSlot
;
521 mPartialScanObj
= NULL
;
523 if (mNumToScan
<0) mNumToScan
= 0;
526 int32 numtoscan
= sc_min(remain
, mNumToScan
);
527 ScanSlots(mPartialScanObj
->slots
+ mPartialScanSlot
, numtoscan
);
529 if (numtoscan
== remain
) {
530 mPartialScanObj
= NULL
;
531 mNumToScan
-= numtoscan
+ 4;
533 mPartialScanSlot
+= numtoscan
;
534 mNumToScan
-= numtoscan
;
536 if (mNumToScan
< 0) mNumToScan
= 0;
537 //post("partial %5d xx %4d %2d %s\n", mScans, mNumToScan, mNumGrey);
538 //post("partial %5d %2d %4d %2d %s\n", mScans, i, mNumToScan, mNumGrey, slotRawSymbol(&obj->classptr->name)->name);
541 HOT
bool PyrGC::ScanOneObj()
543 // Find a set that has a grey object
545 obj
= (PyrObject
*)mGrey
.next
;
547 if (mNumGrey
) fatalerror("grey count error\n");
551 /*if (!IsGrey(obj)) {
552 postfl("Object on grey list not grey %d %d\n", obj->gc_color, mGreyColor);
558 //post("-> scan %d %d %d\n", mNumGrey, IsGrey(obj), mNumToScan);
559 // Found a grey object
560 // move obj from grey to black
564 int32 size
= ScanSize(obj
);
565 //post("<- scan %d %d %d %d\n", mNumGrey, IsGrey(obj), mNumToScan, size);
566 if (size
> mNumToScan
+ 32)
568 mPartialScanObj
= obj
;
569 mPartialScanSlot
= 0;
574 ScanSlots(obj
->slots
, size
);
575 mNumToScan
-= 1L << obj
->obj_sizeclass
;
576 if (mNumToScan
< 0) mNumToScan
= 0;
578 mNumToScan
-= 1L << obj
->obj_sizeclass
;
579 if (mNumToScan
< 0) mNumToScan
= 0;
584 void PyrGC::ScanStack()
587 PyrObject
* obj
= mStack
;
589 VMGlobals
*g
= mVMGlobals
;
591 PyrSlot
* slot
= obj
->slots
;
592 int32 size
= obj
->size
= g
->sp
- slot
+ 1;
594 ScanSlots(slot
, size
);
597 void PyrGC::ScanFrames()
599 VMGlobals
*g
= mVMGlobals
;
600 PyrFrame
* frame
= g
->frame
;
603 // this is more incremental
604 if (IsWhite(frame
)) {
608 // this is more efficient
609 if (!IsBlack(frame
)) {
611 int32 size
= ScanSize(frame
);
612 PyrSlot
*slots
= ((PyrObject
*)frame
)->slots
;
613 ScanSlots(slots
, size
);
616 frame
= slotRawFrame(&frame
->caller
);
622 #ifdef GC_SANITYCHECK
629 if ((mFlips
& 3) == 0) {
631 for (int i
=0; i
<kNumGCSets
; ++i
, ++gcs
) {
642 for (int i
=0; i
<kNumGCSets
; ++i
, ++gcs
) {
646 // move root to grey area
657 //post("flips %d collects %d nalloc %d alloc %d grey %d\n", mFlips, mCollects, mNumAllocs, mAllocTotal, mNumGrey);
659 #ifdef GC_SANITYCHECK
665 void PyrGC::FullCollection()
667 Collect(100000000); // collect space
671 void PyrGC::Collect(int32 inNumToScan
)
673 mNumToScan
= sc_max(mNumToScan
, inNumToScan
);
674 Collect(); // collect space
677 HOT
void PyrGC::Collect()
680 bool stackScanned
= false;
683 #ifdef GC_SANITYCHECK
687 if (mNumToScan
> 0) {
688 //post("->Collect ns %d ng %d s %d\n", mNumToScan, mNumGrey, mScans);
690 mNumToScan
+= mNumToScan
>> 3;
692 //post("->Collect2 ns %d ng %d s %d\n", mNumToScan, mNumGrey, mScans);
694 while (mNumToScan
> 0) {
695 while (mNumToScan
> 0 && (mNumGrey
> 0 || mPartialScanObj
)) {
696 if (mPartialScanObj
) {
697 DoPartialScan(ScanSize(mPartialScanObj
));
699 if (!ScanOneObj()) break;
702 if (mNumGrey
== 0 && mPartialScanObj
== NULL
) {
709 if (mNumGrey
== 0 && mPartialScanObj
== NULL
&& stackScanned
) {
715 //post("<-Collect ns %d ng %d s %d\n", mNumToScan, mNumGrey, mScans);
718 //TraceAnyPathToObjsOfSize(9);
720 //TraceAnyPathToAllGrey();
722 //post("mNumToScan %d\n", mNumToScan);
724 mUncollectedAllocations
= 0;
725 #ifdef GC_SANITYCHECK
733 void PyrGC::Finalize(PyrObject
*finalizer
)
735 if (!IsPtr(finalizer
->slots
+0)) return;
736 if (!IsObj(finalizer
->slots
+1)) return;
738 ObjFuncPtr func
= (ObjFuncPtr
)slotRawPtr(&finalizer
->slots
[0]);
739 PyrObject
*obj
= slotRawObject(&finalizer
->slots
[1]);
740 //post("FINALIZE %s %p\n", slotRawSymbol(&obj->classptr->name)->name, obj);
741 (func
)(mVMGlobals
, obj
);
743 SetNil(obj
->slots
+0);
744 SetNil(obj
->slots
+1);
747 void PyrGC::ScanFinalizers()
749 GCSet
*gcs
= &mSets
[kFinalizerSet
];
750 PyrObjectHdr
*obj
= gcs
->mWhite
.next
;
751 PyrObjectHdr
*firstFreeObj
= gcs
->mFree
;
753 while (obj
!= firstFreeObj
) {
754 Finalize((PyrObject
*)obj
);
759 void PyrGC::RunAllFinalizers()
761 GCSet
*gcs
= &mSets
[kFinalizerSet
];
763 PyrObjectHdr
*obj
= gcs
->mBlack
.next
;
764 while (!IsMarker(obj
)) {
765 Finalize((PyrObject
*)obj
);
769 obj
= gcs
->mWhite
.next
;
770 PyrObjectHdr
*firstFreeObj
= gcs
->mFree
;
771 while (obj
!= firstFreeObj
) {
772 Finalize((PyrObject
*)obj
);
777 while (!IsMarker(obj
)) {
778 if (obj
->classptr
== class_finalizer
)
779 Finalize((PyrObject
*)obj
);
784 bool PyrGC::SanityCheck2()
787 PyrObjectHdr
*grey
= mGrey
.next
;
788 while (!IsMarker(grey
)) {
791 postfl("sc Object on grey list not grey %d %d %d\n", grey
->gc_color
, mGreyColor
, numgrey
);
796 //postfl("sc %d %d\n", mNumGrey, numgrey);
797 return mNumGrey
== numgrey
;
801 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>
804 bool PyrGC::SanityCheck()
806 if (!mRunning
) return true;
808 //postfl("PyrGC::SanityCheck\n");
809 bool res
= LinkSanity() && ListSanity()
810 // && SanityMarkObj((PyrObject*)mProcess,NULL,0) && SanityMarkObj(mStack,NULL,0)
811 // && SanityClearObj((PyrObject*)mProcess,0) && SanityClearObj(mStack,0)
814 //if (!res) DumpInfo();
815 //if (!res) Debugger();
819 bool PyrGC::ListSanity()
823 if (StackDepth() < 0) {
824 fprintf(stderr
, "stack underflow %d\n", (int)StackDepth());
828 //postfl("PyrGC::ListSanity\n");
829 for (int i
=0; i
<kNumGCSets
; ++i
) {
831 GCSet
* set
= mSets
+ i
;
833 // check black marker
835 if (!IsMarker(obj
)) {
836 //debugf("set %d black marker color wrong %d %p\n", i, obj->gc_color, obj);
837 fprintf(stderr
, "set %d black marker color wrong %d %p\n", i
, obj
->gc_color
, obj
);
839 DumpBackTrace(mVMGlobals
);
840 dumpBadObject((PyrObject
*)obj
);
844 // check white marker
846 if (!IsMarker(obj
)) {
847 //debugf("set %d white marker color wrong %d %p\n", i, obj->gc_color, obj);
848 fprintf(stderr
, "set %d white marker color wrong %d %p\n", i
, obj
->gc_color
, obj
);
850 DumpBackTrace(mVMGlobals
);
851 dumpBadObject((PyrObject
*)obj
);
855 // check free pointer between white and black marker
856 if (set
->mFree
!= &set
->mBlack
) {
857 obj
= set
->mWhite
.next
;
859 while (!IsMarker(obj
)) {
860 if (obj
== set
->mFree
) { found
= true; break; }
864 //debugf("set %d free pointer not between white and black\n", i);
865 fprintf(stderr
, "set %d free pointer not between white and black\n", i
);
866 fprintf(stderr
, "set->mFree %p\n", set
->mFree
);
867 fprintf(stderr
, "set->mWhite %p\n", &set
->mWhite
);
868 fprintf(stderr
, "set->mBlack %p\n", &set
->mBlack
);
870 DumpBackTrace(mVMGlobals
);
871 dumpBadObject((PyrObject
*)set
->mFree
);
873 fprintf(stderr
, "black %d white %d grey %d\n", mBlackColor
, mWhiteColor
, mGreyColor
);
878 if (obj
== set
->mFree
) fprintf(stderr
, "%4d %p %3d %d FREE\n", count
, obj
, obj
->gc_color
, obj
->obj_sizeclass
);
879 else if (obj
== &set
->mWhite
) fprintf(stderr
, "%4d %p %3d %d WHITE\n", count
, obj
, obj
->gc_color
, obj
->obj_sizeclass
);
880 else if (obj
== &set
->mBlack
) fprintf(stderr
, "%4d %p %3d %d BLACK\n", count
, obj
, obj
->gc_color
, obj
->obj_sizeclass
);
881 else fprintf(stderr
, "%4d %p %3d %d\n", count
, obj
, obj
->gc_color
, obj
->obj_sizeclass
);
884 } while (obj
!= &set
->mWhite
);
891 obj
= set
->mBlack
.next
;
892 while (!IsMarker(obj
)) {
893 if (obj
->gc_color
!= mBlackColor
) {
894 //debugf("set %d black list obj color wrong %d (%d, %d, %d) %p\n",
895 // i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj);
896 fprintf(stderr
, "set %d black list obj color wrong %d (%d, %d, %d) %p\n",
897 i
, obj
->gc_color
, mBlackColor
, mGreyColor
, mWhiteColor
, obj
);
899 DumpBackTrace(mVMGlobals
);
900 dumpBadObject((PyrObject
*)obj
);
903 if (GetGCSet(obj
) != set
) {
904 //debugf("set %d black obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj);
905 fprintf(stderr
, "set %d black obj gcset wrong %d %p\n", i
, obj
->obj_sizeclass
, obj
);
907 dumpBadObject((PyrObject
*)obj
);
910 if (obj
->next
->prev
!= obj
) {
911 fprintf(stderr
, "set %d black obj->next->prev != obj\n", i
);
913 DumpBackTrace(mVMGlobals
);
914 dumpBadObject((PyrObject
*)obj
);
917 // scan for refs to white.
918 if (!BlackToWhiteCheck((PyrObject
*)obj
)) return false;
924 obj
= set
->mWhite
.next
;
925 while (obj
!= set
->mFree
) {
926 if (obj
->gc_color
!= mWhiteColor
) {
927 //debugf("set %d white list obj color wrong %d (%d, %d, %d) %p\n",
928 // i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj);
929 //debugf("hmmm free %p black %p\n", set->mFree, set->black);
930 fprintf(stderr
, "set %d white list obj color wrong %d (%d, %d, %d) %p\n",
931 i
, obj
->gc_color
, mBlackColor
, mGreyColor
, mWhiteColor
, obj
);
932 fprintf(stderr
, "hmmm free %p black %p\n", set
->mFree
, &set
->mBlack
);
934 DumpBackTrace(mVMGlobals
);
935 dumpBadObject((PyrObject
*)obj
);
938 if (GetGCSet(obj
) != set
) {
939 //debugf("set %d white obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj);
940 fprintf(stderr
, "set %d white obj gcset wrong %d %p\n", i
, obj
->obj_sizeclass
, obj
);
942 DumpBackTrace(mVMGlobals
);
943 dumpBadObject((PyrObject
*)obj
);
946 if (obj
->next
->prev
!= obj
) {
947 fprintf(stderr
, "set %d white obj->next->prev != obj\n", i
);
949 DumpBackTrace(mVMGlobals
);
950 dumpBadObject((PyrObject
*)obj
);
955 // mark all free list items free
957 while (!IsMarker(obj
)) {
958 /*if (obj->gc_color == mGreyColor) {
959 //debugf("grey obj on free list\n");
960 fprintf(stderr, "grey obj on free list\n");
964 //dumpObject((PyrObject*)(PyrObject*)obj);
965 obj
->gc_color
= mFreeColor
;
966 if (GetGCSet(obj
) != set
) {
967 //debugf("set %d free obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj);
968 fprintf(stderr
, "set %d free obj gcset wrong %d %p\n", i
, obj
->obj_sizeclass
, obj
);
969 //dumpObject((PyrObject*)obj);
972 if (obj
->next
->prev
!= obj
) {
973 fprintf(stderr
, "set %d free obj->next->prev != obj\n", i
);
974 //dumpObject((PyrObject*)obj);
981 PyrObjectHdr
*grey
= mGrey
.next
;
982 while (!IsMarker(grey
)) {
985 fprintf(stderr
, "sc Object on grey list not grey %d %d %d\n", grey
->gc_color
, mGreyColor
, numgrey
);
986 fprintf(stderr
, "%p <- %p -> %p grey %p process %p\n", mGrey
.prev
, &mGrey
, mGrey
.next
, grey
, mProcess
);
992 if (numgrey
!= mNumGrey
) {
993 fprintf(stderr
, "grey count off %d %d\n", numgrey
, mNumGrey
);
995 fprintf(stderr
, ".");
1001 bool PyrGC::LinkSanity()
1003 //postfl("PyrGC::LinkSanity\n");
1004 for (int i
=0; i
<kNumGCSets
; ++i
) {
1005 GCSet
* set
= mSets
+ i
;
1008 PyrObjectHdr
* obj
= &set
->mBlack
;
1010 if (obj
->next
->prev
!= obj
) {
1011 fprintf(stderr
, "set %d black obj->next->prev != obj\n", i
);
1012 //dumpObject((PyrObject*)obj);
1015 if (obj
->prev
->next
!= obj
) {
1016 fprintf(stderr
, "set %d black obj->prev->next != obj\n", i
);
1017 //dumpObject((PyrObject*)obj);
1021 } while (obj
!= &set
->mBlack
);
1026 #define DUMPINSANITY 1
1028 bool PyrGC::BlackToWhiteCheck(PyrObject
*objA
)
1030 if (objA
->obj_format
> obj_slot
) return true;
1032 int size
= objA
->size
;
1034 PyrSlot
*slot
= objA
->slots
;
1035 for (int j
=size
; j
--; ++slot
) {
1036 PyrObject
* objB
= NULL
;
1037 if (IsObj(slot
) && slotRawObject(slot
)) {
1038 objB
= slotRawObject(slot
);
1040 if (objB
&& (unsigned long)objB
< 100) {
1041 fprintf(stderr
, "weird obj ptr\n");
1048 if (objA
->gc_color
== mBlackColor
&& objA
!= mPartialScanObj
) {
1049 if (objB
->gc_color
== mWhiteColor
) {
1050 if (objA
->classptr
== class_frame
) {
1051 // jmc: black stack frames pointing to white nodes can be ignore
1052 PyrFrame
* frameA
= (PyrFrame
*)objA
;
1053 PyrMethod
* meth
= slotRawMethod(&frameA
->method
);
1054 PyrMethodRaw
* methraw
= METHRAW(meth
);
1055 if (methraw
->needsHeapContext
)
1059 fprintf(stderr
, "black frame to white ref %p %p\n", objA
, objB
);
1060 dumpBadObject(objA
);
1061 dumpBadObject(objB
);
1062 fprintf(stderr
, "\n");
1073 bool PyrGC::SanityMarkObj(PyrObject
*objA
, PyrObject
*fromObj
, int level
)
1075 if (objA
->IsPermanent()) return true;
1076 if (objA
->IsMarked()) return true;
1077 if (objA
->size
> MAXINDEXSIZE(objA
)) {
1078 fprintf(stderr
, "obj indexed size larger than max: %d > %d\n", objA
->size
, MAXINDEXSIZE(objA
));
1079 //dumpObject((PyrObject*)objA);
1083 objA
->SetMark(); // mark it
1084 if (!BlackToWhiteCheck(objA
))
1087 if (objA
->obj_format
<= obj_slot
) {
1089 int size
= objA
->size
;
1091 PyrSlot
*slot
= objA
->slots
;
1092 for (int j
=size
; j
--; ++slot
) {
1093 PyrObject
* objB
= NULL
;
1094 int tag
= GetTag(slot
);
1095 if (tag
== tagObj
&& slotRawObject(slot
))
1096 objB
= slotRawObject(slot
);
1101 fprintf(stderr, "40 levels deep!\n");
1102 dumpBadObject(objA);
1103 dumpBadObject(objB);
1106 bool err
= SanityMarkObj(objB
, objA
, level
+ 1);
1116 bool PyrGC::SanityClearObj(PyrObject
*objA
, int level
)
1118 if (!(objA
->IsMarked())) return true;
1119 if (objA
->IsPermanent()) return true;
1120 objA
->ClearMark(); // unmark it
1122 if (objA
->obj_format
<= obj_slot
) {
1124 int size
= objA
->size
;
1126 PyrSlot
*slot
= objA
->slots
;
1127 for (int j
=size
; j
--; ++slot
) {
1128 PyrObject
*objB
= NULL
;
1129 if (IsObj(slot
) && slotRawObject(slot
)) {
1130 objB
= slotRawObject(slot
);
1134 fprintf(stderr, "40 levels deep!\n");
1135 dumpBadObject(objA);
1136 //dumpObject((PyrObject*)objB); //newPyrFrame
1139 bool err
= SanityClearObj(objB
, level
+1);
1140 if (!err
) return false;
1148 void PyrGC::DumpInfo()
1152 int numblack
, numwhite
, numfree
, settotal
, setsiztotal
;
1153 int totblack
, totgrey
, totwhite
, totfree
, totref
, total
, siztotal
;
1156 post("flips %d collects %d nalloc %d alloc %d grey %d\n", mFlips
, mCollects
, mNumAllocs
, mAllocTotal
, mNumGrey
);
1165 for (i
=0; i
<kNumGCSizeClasses
; ++i
) {
1166 GCSet
*set
= mSets
+ i
;
1170 obj
= set
->mBlack
.next
;
1171 while (!IsMarker(obj
)) {
1178 obj
= set
->mWhite
.next
;
1179 while (obj
!= set
->mFree
) {
1187 while (!IsMarker(obj
)) {
1191 settotal
= numblack
+ numwhite
+ numfree
;
1192 setsiztotal
= settotal
<< (i
+ 3);
1193 siztotal
+= setsiztotal
;
1194 totblack
+= numblack
;
1195 totwhite
+= numwhite
;
1199 post("%2d bwf t sz: %6d %6d %6d %6d %8d\n", i
,
1200 numblack
, numwhite
, numfree
, settotal
, setsiztotal
);
1203 post("tot bwf t sz: %6d %6d %6d %6d %8d\n",
1204 totblack
, totwhite
, totfree
, total
, siztotal
);
1207 void PyrGC::DumpGrey()
1211 PyrObjectHdr
*obj
= mGrey
.next
;
1212 while (!IsMarker(obj
)) {
1213 post("grey %s %d %d\n", slotRawSymbol(&obj
->classptr
->name
)->name
, obj
->obj_sizeclass
, obj
->size
);
1218 void PyrGC::DumpSet(int i
)
1220 GCSet
*set
= mSets
+ i
;
1223 PyrObjectHdr
*obj
= set
->mBlack
.next
;
1224 while (!IsMarker(obj
)) {
1225 post("black %s %d %d\n", slotRawSymbol(&obj
->classptr
->name
)->name
, obj
->obj_sizeclass
, obj
->size
);
1230 obj
= set
->mWhite
.next
;
1231 while (obj
!= set
->mFree
) {
1232 post("white %s %d %d\n", slotRawSymbol(&obj
->classptr
->name
)->name
, obj
->obj_sizeclass
, obj
->size
);
1238 while (!IsMarker(obj
)) {
1239 post("free %s %d %d\n", slotRawSymbol(&obj
->classptr
->name
)->name
, obj
->obj_sizeclass
, obj
->size
);
1244 void PyrGC::ClearMarks()
1246 for (int i
=0; i
<kNumGCSets
; ++i
) {
1247 GCSet
*set
= mSets
+ i
;
1250 PyrObjectHdr
*obj
= set
->mBlack
.next
;
1251 while (!IsMarker(obj
)) {
1252 obj
->ClearMark(); // unmark it
1258 while (!IsMarker(obj
)) {
1259 obj
->ClearMark(); // unmark it
1264 obj
= set
->mWhite
.next
;
1265 while (obj
!= set
->mFree
) {
1266 obj
->ClearMark(); // unmark it
1272 while (!IsMarker(obj
)) {
1273 obj
->ClearMark(); // unmark it
1279 void PyrGC::throwMemfailed(size_t inNumBytes
)
1281 post("alloc failed. size = %d\n", inNumBytes
);