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 void PyrGC::ScanSlots(PyrSlot
*inSlots
, long inNumToScan
)
152 unsigned char whiteColor
= mWhiteColor
;
154 PyrSlot
*slot
= inSlots
;
155 PyrSlot
*endslot
= inSlots
+ inNumToScan
;
156 for (; slot
< endslot
; ++slot
) {
158 PyrObject
*obj
= slotRawObject(slot
);
159 if (obj
->gc_color
== whiteColor
) {
164 mSlotsScanned
+= inNumToScan
;
167 void GCSet::Init(int inGCSet
)
169 mBlack
.classptr
= NULL
;
170 mBlack
.obj_sizeclass
= inGCSet
;
172 mBlack
.gc_color
= obj_gcmarker
;
174 mWhite
.classptr
= NULL
;
175 mWhite
.obj_sizeclass
= inGCSet
;
177 mWhite
.gc_color
= obj_gcmarker
;
181 mBlack
.next
= &mWhite
;
182 mWhite
.next
= &mBlack
;
184 mBlack
.prev
= &mWhite
;
185 mWhite
.prev
= &mBlack
;
189 void GCSet::MajorFlip()
191 // move all white items to beginning of free list
193 if (!PyrGC::IsMarker(mBlack
.next
)) {
194 // move all black items to white list
195 mWhite
.next
= mBlack
.next
;
196 mFree
->prev
= mWhite
.prev
;
197 mBlack
.next
->prev
= &mWhite
;
198 mWhite
.prev
->next
= mFree
;
201 mBlack
.next
= &mWhite
;
202 mWhite
.prev
= &mBlack
;
206 void GCSet::MinorFlip()
208 // move all white items to beginning of free list
212 PyrProcess
* newPyrProcess(VMGlobals
*g
, PyrClass
*procclassobj
);
214 PyrGC::PyrGC(VMGlobals
*g
, AllocPool
*inPool
, PyrClass
*mainProcessClass
, long poolSize
)
227 mNumPartialScans
= 0;
238 mPartialScanObj
= NULL
;
239 mPartialScanSlot
= 0;
240 mUncollectedAllocations
= 0;
242 mGrey
.classptr
= NULL
;
243 mGrey
.obj_sizeclass
= 0;
245 mGrey
.gc_color
= obj_gcmarker
;
252 mNewPool
.Init(mPool
, poolSize
, poolSize
, 9000);
254 // initialize treadmills
255 for (int i
=0; i
<kNumGCSets
; ++i
) {
258 g
->process
= NULL
; // initPyrThread checks to see if process has been started
259 mProcess
= newPyrProcess(g
, mainProcessClass
);
261 mStack
= slotRawObject(&slotRawThread(&mProcess
->mainThread
)->stack
);
263 SetNil(&slotRawThread(&mProcess
->mainThread
)->stack
);
267 g
->sp
= mStack
->slots
- 1;
268 g
->process
= mProcess
;
272 //assert(SanityCheck());
276 PyrObject
*PyrGC::NewPermanent(size_t inNumBytes
, long inFlags
, long inFormat
)
279 int32 alignedSize
= (inNumBytes
+ kAlignMask
) & ~kAlignMask
; // 16 byte align
280 int32 numSlots
= alignedSize
/ sizeof(PyrSlot
);
281 numSlots
= numSlots
< 1 ? 1 : numSlots
;
282 int32 sizeclass
= LOG2CEIL(numSlots
);
283 sizeclass
= sc_min(sizeclass
, kNumGCSizeClasses
-1);
285 int32 allocSize
= sizeof(PyrObjectHdr
) + (sizeof(PyrSlot
) << sizeclass
);
287 // allocate permanent objects
288 PyrObject
* obj
= (PyrObject
*)pyr_pool_runtime
->Alloc(allocSize
);
290 obj
->gc_color
= obj_permanent
;
291 obj
->next
= obj
->prev
= NULL
;
292 obj
->obj_sizeclass
= sizeclass
;
293 obj
->obj_format
= inFormat
;
294 obj
->obj_flags
= inFlags
;
296 obj
->classptr
= class_object
;
300 void PyrGC::BecomePermanent(PyrObject
*inObject
)
303 if (IsGrey(inObject
)) mNumGrey
--;
305 inObject
->gc_color
= obj_permanent
;
306 inObject
->obj_flags
|= obj_immutable
;
307 inObject
->next
= inObject
->prev
= inObject
;
310 void PyrGC::BecomeImmutable(PyrObject
*inObject
)
312 inObject
->obj_flags
|= obj_immutable
;
315 void DumpBackTrace(VMGlobals
*g
);
317 PyrObject
*PyrGC::New(size_t inNumBytes
, long inFlags
, long inFormat
, bool inCollect
)
319 PyrObject
*obj
= NULL
;
321 if (inFlags
& obj_permanent
) {
322 return NewPermanent(inNumBytes
, inFlags
, inFormat
);
325 #ifdef GC_SANITYCHECK
331 int32 alignedSize
= (inNumBytes
+ kAlignMask
) & ~kAlignMask
; // 16 byte align
332 int32 numSlots
= alignedSize
/ sizeof(PyrSlot
);
333 numSlots
= numSlots
< 1 ? 1 : numSlots
;
334 int32 sizeclass
= LOG2CEIL(numSlots
);
335 sizeclass
= sc_min(sizeclass
, kNumGCSizeClasses
-1);
337 int32 credit
= 1L << sizeclass
;
338 mAllocTotal
+= credit
;
341 mNumToScan
+= credit
;
342 obj
= Allocate(inNumBytes
, sizeclass
, inCollect
);
344 obj
->obj_format
= inFormat
;
345 obj
->obj_flags
= inFlags
& 255;
347 obj
->classptr
= class_object
;
348 obj
->gc_color
= mWhiteColor
;
350 #ifdef GC_SANITYCHECK
358 PyrObject
*PyrGC::NewFrame(size_t inNumBytes
, long inFlags
, long inFormat
, bool inAccount
)
360 PyrObject
*obj
= NULL
;
362 #ifdef GC_SANITYCHECK
368 int32 alignedSize
= (inNumBytes
+ kAlignMask
) & ~kAlignMask
; // 16 byte align
369 int32 numSlots
= alignedSize
/ sizeof(PyrSlot
);
370 numSlots
= numSlots
< 1 ? 1 : numSlots
;
371 int32 sizeclass
= LOG2CEIL(numSlots
);
372 sizeclass
= sc_min(sizeclass
, kNumGCSizeClasses
-1);
374 int32 credit
= 1L << sizeclass
;
375 mAllocTotal
+= credit
;
377 mNumToScan
+= credit
;
379 obj
= Allocate(inNumBytes
, sizeclass
, inAccount
);
381 obj
->obj_format
= inFormat
;
382 obj
->obj_flags
= inFlags
;
384 obj
->classptr
= class_frame
;
385 obj
->gc_color
= mWhiteColor
;
387 #ifdef GC_SANITYCHECK
393 PyrObject
*PyrGC::NewFinalizer(ObjFuncPtr finalizeFunc
, PyrObject
*inObject
, bool inCollect
)
395 PyrObject
*obj
= NULL
;
397 #ifdef GC_SANITYCHECK
405 int32 credit
= 1L << sizeclass
;
406 mNumToScan
+= credit
;
407 mAllocTotal
+= credit
;
410 if (inCollect
&& mNumToScan
>= kScanThreshold
) {
414 GCSet
*gcs
= mSets
+ kFinalizerSet
;
416 obj
= (PyrObject
*)gcs
->mFree
;
417 if (!IsMarker(obj
)) {
419 gcs
->mFree
= obj
->next
;
421 if (sizeclass
> kMaxPoolSet
) {
423 int32 allocSize
= sizeof(PyrObjectHdr
) + (sizeof(PyrSlot
) << sizeclass
);
424 obj
= (PyrObject
*)mPool
->Alloc(allocSize
);
426 int32 allocSize
= sizeof(PyrObjectHdr
) + (sizeof(PyrSlot
) << sizeclass
);
427 obj
= (PyrObject
*)mNewPool
.Alloc(allocSize
);
430 post("Finalizer alloc failed.\n");
433 DLInsertAfter(&gcs
->mWhite
, obj
);
437 obj
->obj_sizeclass
= sizeclass
;
438 obj
->obj_format
= obj_slot
;
441 obj
->classptr
= class_finalizer
;
442 obj
->gc_color
= mWhiteColor
;
444 SetPtr(obj
->slots
+0, (void*)finalizeFunc
);
445 SetObject(obj
->slots
+1, inObject
);
447 #ifdef GC_SANITYCHECK
454 void PyrGC::SweepBigObjects()
456 if (!mCanSweep
) return;
458 for (int i
=kMaxPoolSet
+1; i
<kNumGCSizeClasses
; ++i
) {
459 GCSet
*gcs
= mSets
+ i
;
460 PyrObjectHdr
*obj
= gcs
->mFree
;
462 if (!IsMarker(obj
)) {
463 // unlink chain of free objects
464 gcs
->mFree
= obj
->prev
->next
= &gcs
->mBlack
;
465 gcs
->mBlack
.prev
= obj
->prev
;
468 PyrObjectHdr
*nextobj
= obj
->next
;
469 void* ptr
= (void*)obj
;
472 } while (!IsMarker(obj
));
478 void PyrGC::CompletePartialScan(PyrObject
*obj
)
480 if (mPartialScanObj
== obj
) {
481 int32 remain
= obj
->size
- mPartialScanSlot
;
482 ScanSlots(mPartialScanObj
->slots
+ mPartialScanSlot
, remain
);
486 void PyrGC::DoPartialScan(int32 inObjSize
)
488 int32 remain
= inObjSize
- mPartialScanSlot
;
491 mPartialScanObj
= NULL
;
493 if (mNumToScan
<0) mNumToScan
= 0;
496 int32 numtoscan
= sc_min(remain
, mNumToScan
);
497 ScanSlots(mPartialScanObj
->slots
+ mPartialScanSlot
, numtoscan
);
499 if (numtoscan
== remain
) {
500 mPartialScanObj
= NULL
;
501 mNumToScan
-= numtoscan
+ 4;
503 mPartialScanSlot
+= numtoscan
;
504 mNumToScan
-= numtoscan
;
506 if (mNumToScan
< 0) mNumToScan
= 0;
507 //post("partial %5d xx %4d %2d %s\n", mScans, mNumToScan, mNumGrey);
508 //post("partial %5d %2d %4d %2d %s\n", mScans, i, mNumToScan, mNumGrey, slotRawSymbol(&obj->classptr->name)->name);
511 bool PyrGC::ScanOneObj()
513 // Find a set that has a grey object
515 obj
= (PyrObject
*)mGrey
.next
;
517 if (mNumGrey
) fatalerror("grey count error\n");
521 /*if (!IsGrey(obj)) {
522 postfl("Object on grey list not grey %d %d\n", obj->gc_color, mGreyColor);
528 //post("-> scan %d %d %d\n", mNumGrey, IsGrey(obj), mNumToScan);
529 // Found a grey object
530 // move obj from grey to black
534 int32 size
= ScanSize(obj
);
535 //post("<- scan %d %d %d %d\n", mNumGrey, IsGrey(obj), mNumToScan, size);
536 if (size
> mNumToScan
+ 32)
538 mPartialScanObj
= obj
;
539 mPartialScanSlot
= 0;
544 ScanSlots(obj
->slots
, size
);
545 mNumToScan
-= 1L << obj
->obj_sizeclass
;
546 if (mNumToScan
< 0) mNumToScan
= 0;
548 mNumToScan
-= 1L << obj
->obj_sizeclass
;
549 if (mNumToScan
< 0) mNumToScan
= 0;
554 void PyrGC::ScanStack()
557 PyrObject
* obj
= mStack
;
559 VMGlobals
*g
= mVMGlobals
;
561 PyrSlot
* slot
= obj
->slots
;
562 int32 size
= obj
->size
= g
->sp
- slot
+ 1;
564 ScanSlots(slot
, size
);
567 void PyrGC::ScanFrames()
569 VMGlobals
*g
= mVMGlobals
;
570 PyrFrame
* frame
= g
->frame
;
573 // this is more incremental
574 if (IsWhite(frame
)) {
578 // this is more efficient
579 if (!IsBlack(frame
)) {
581 int32 size
= ScanSize(frame
);
582 PyrSlot
*slots
= ((PyrObject
*)frame
)->slots
;
583 ScanSlots(slots
, size
);
586 frame
= slotRawFrame(&frame
->caller
);
592 #ifdef GC_SANITYCHECK
599 if ((mFlips
& 3) == 0) {
601 for (int i
=0; i
<kNumGCSets
; ++i
, ++gcs
) {
612 for (int i
=0; i
<kNumGCSets
; ++i
, ++gcs
) {
616 // move root to grey area
627 //post("flips %d collects %d nalloc %d alloc %d grey %d\n", mFlips, mCollects, mNumAllocs, mAllocTotal, mNumGrey);
629 #ifdef GC_SANITYCHECK
635 void PyrGC::FullCollection()
637 Collect(100000000); // collect space
641 void PyrGC::Collect(int32 inNumToScan
)
643 mNumToScan
= sc_max(mNumToScan
, inNumToScan
);
644 Collect(); // collect space
647 void PyrGC::Collect()
650 bool stackScanned
= false;
653 #ifdef GC_SANITYCHECK
657 if (mNumToScan
> 0) {
658 //post("->Collect ns %d ng %d s %d\n", mNumToScan, mNumGrey, mScans);
660 mNumToScan
+= mNumToScan
>> 3;
662 //post("->Collect2 ns %d ng %d s %d\n", mNumToScan, mNumGrey, mScans);
664 while (mNumToScan
> 0) {
665 while (mNumToScan
> 0 && (mNumGrey
> 0 || mPartialScanObj
)) {
666 if (mPartialScanObj
) {
667 DoPartialScan(ScanSize(mPartialScanObj
));
669 if (!ScanOneObj()) break;
672 if (mNumGrey
== 0 && mPartialScanObj
== NULL
) {
679 if (mNumGrey
== 0 && mPartialScanObj
== NULL
&& stackScanned
) {
685 //post("<-Collect ns %d ng %d s %d\n", mNumToScan, mNumGrey, mScans);
688 //TraceAnyPathToObjsOfSize(9);
690 //TraceAnyPathToAllGrey();
692 //post("mNumToScan %d\n", mNumToScan);
694 mUncollectedAllocations
= 0;
695 #ifdef GC_SANITYCHECK
703 void PyrGC::Finalize(PyrObject
*finalizer
)
705 if (!IsPtr(finalizer
->slots
+0)) return;
706 if (!IsObj(finalizer
->slots
+1)) return;
708 ObjFuncPtr func
= (ObjFuncPtr
)slotRawPtr(&finalizer
->slots
[0]);
709 PyrObject
*obj
= slotRawObject(&finalizer
->slots
[1]);
710 //post("FINALIZE %s %p\n", slotRawSymbol(&obj->classptr->name)->name, obj);
711 (func
)(mVMGlobals
, obj
);
713 SetNil(obj
->slots
+0);
714 SetNil(obj
->slots
+1);
717 void PyrGC::ScanFinalizers()
719 GCSet
*gcs
= &mSets
[kFinalizerSet
];
720 PyrObjectHdr
*obj
= gcs
->mWhite
.next
;
721 PyrObjectHdr
*firstFreeObj
= gcs
->mFree
;
723 while (obj
!= firstFreeObj
) {
724 Finalize((PyrObject
*)obj
);
729 bool PyrGC::SanityCheck2()
732 PyrObjectHdr
*grey
= mGrey
.next
;
733 while (!IsMarker(grey
)) {
736 postfl("sc Object on grey list not grey %d %d %d\n", grey
->gc_color
, mGreyColor
, numgrey
);
741 //postfl("sc %d %d\n", mNumGrey, numgrey);
742 return mNumGrey
== numgrey
;
746 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacTypes.h>
749 bool PyrGC::SanityCheck()
751 if (!mRunning
) return true;
753 //postfl("PyrGC::SanityCheck\n");
754 bool res
= LinkSanity() && ListSanity()
755 // && SanityMarkObj((PyrObject*)mProcess,NULL,0) && SanityMarkObj(mStack,NULL,0)
756 // && SanityClearObj((PyrObject*)mProcess,0) && SanityClearObj(mStack,0)
759 //if (!res) DumpInfo();
760 //if (!res) Debugger();
764 bool PyrGC::ListSanity()
768 if (StackDepth() < 0) {
769 fprintf(stderr
, "stack underflow %d\n", (int)StackDepth());
773 //postfl("PyrGC::ListSanity\n");
774 for (int i
=0; i
<kNumGCSets
; ++i
) {
776 GCSet
* set
= mSets
+ i
;
778 // check black marker
780 if (!IsMarker(obj
)) {
781 //debugf("set %d black marker color wrong %d %p\n", i, obj->gc_color, obj);
782 fprintf(stderr
, "set %d black marker color wrong %d %p\n", i
, obj
->gc_color
, obj
);
784 DumpBackTrace(mVMGlobals
);
785 dumpBadObject((PyrObject
*)obj
);
789 // check white marker
791 if (!IsMarker(obj
)) {
792 //debugf("set %d white marker color wrong %d %p\n", i, obj->gc_color, obj);
793 fprintf(stderr
, "set %d white marker color wrong %d %p\n", i
, obj
->gc_color
, obj
);
795 DumpBackTrace(mVMGlobals
);
796 dumpBadObject((PyrObject
*)obj
);
800 // check free pointer between white and black marker
801 if (set
->mFree
!= &set
->mBlack
) {
802 obj
= set
->mWhite
.next
;
804 while (!IsMarker(obj
)) {
805 if (obj
== set
->mFree
) { found
= true; break; }
809 //debugf("set %d free pointer not between white and black\n", i);
810 fprintf(stderr
, "set %d free pointer not between white and black\n", i
);
811 fprintf(stderr
, "set->mFree %p\n", set
->mFree
);
812 fprintf(stderr
, "set->mWhite %p\n", &set
->mWhite
);
813 fprintf(stderr
, "set->mBlack %p\n", &set
->mBlack
);
815 DumpBackTrace(mVMGlobals
);
816 dumpBadObject((PyrObject
*)set
->mFree
);
818 fprintf(stderr
, "black %d white %d grey %d\n", mBlackColor
, mWhiteColor
, mGreyColor
);
823 if (obj
== set
->mFree
) fprintf(stderr
, "%4d %p %3d %d FREE\n", count
, obj
, obj
->gc_color
, obj
->obj_sizeclass
);
824 else if (obj
== &set
->mWhite
) fprintf(stderr
, "%4d %p %3d %d WHITE\n", count
, obj
, obj
->gc_color
, obj
->obj_sizeclass
);
825 else if (obj
== &set
->mBlack
) fprintf(stderr
, "%4d %p %3d %d BLACK\n", count
, obj
, obj
->gc_color
, obj
->obj_sizeclass
);
826 else fprintf(stderr
, "%4d %p %3d %d\n", count
, obj
, obj
->gc_color
, obj
->obj_sizeclass
);
829 } while (obj
!= &set
->mWhite
);
836 obj
= set
->mBlack
.next
;
837 while (!IsMarker(obj
)) {
838 if (obj
->gc_color
!= mBlackColor
) {
839 //debugf("set %d black list obj color wrong %d (%d, %d, %d) %p\n",
840 // i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj);
841 fprintf(stderr
, "set %d black list obj color wrong %d (%d, %d, %d) %p\n",
842 i
, obj
->gc_color
, mBlackColor
, mGreyColor
, mWhiteColor
, obj
);
844 DumpBackTrace(mVMGlobals
);
845 dumpBadObject((PyrObject
*)obj
);
848 if (GetGCSet(obj
) != set
) {
849 //debugf("set %d black obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj);
850 fprintf(stderr
, "set %d black obj gcset wrong %d %p\n", i
, obj
->obj_sizeclass
, obj
);
852 dumpBadObject((PyrObject
*)obj
);
855 if (obj
->next
->prev
!= obj
) {
856 fprintf(stderr
, "set %d black obj->next->prev != obj\n", i
);
858 DumpBackTrace(mVMGlobals
);
859 dumpBadObject((PyrObject
*)obj
);
862 // scan for refs to white.
863 if (!BlackToWhiteCheck((PyrObject
*)obj
)) return false;
869 obj
= set
->mWhite
.next
;
870 while (obj
!= set
->mFree
) {
871 if (obj
->gc_color
!= mWhiteColor
) {
872 //debugf("set %d white list obj color wrong %d (%d, %d, %d) %p\n",
873 // i, obj->gc_color, mBlackColor, mGreyColor, mWhiteColor, obj);
874 //debugf("hmmm free %p black %p\n", set->mFree, set->black);
875 fprintf(stderr
, "set %d white list obj color wrong %d (%d, %d, %d) %p\n",
876 i
, obj
->gc_color
, mBlackColor
, mGreyColor
, mWhiteColor
, obj
);
877 fprintf(stderr
, "hmmm free %p black %p\n", set
->mFree
, &set
->mBlack
);
879 DumpBackTrace(mVMGlobals
);
880 dumpBadObject((PyrObject
*)obj
);
883 if (GetGCSet(obj
) != set
) {
884 //debugf("set %d white obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj);
885 fprintf(stderr
, "set %d white obj gcset wrong %d %p\n", i
, obj
->obj_sizeclass
, obj
);
887 DumpBackTrace(mVMGlobals
);
888 dumpBadObject((PyrObject
*)obj
);
891 if (obj
->next
->prev
!= obj
) {
892 fprintf(stderr
, "set %d white obj->next->prev != obj\n", i
);
894 DumpBackTrace(mVMGlobals
);
895 dumpBadObject((PyrObject
*)obj
);
900 // mark all free list items free
902 while (!IsMarker(obj
)) {
903 /*if (obj->gc_color == mGreyColor) {
904 //debugf("grey obj on free list\n");
905 fprintf(stderr, "grey obj on free list\n");
909 //dumpObject((PyrObject*)(PyrObject*)obj);
910 obj
->gc_color
= mFreeColor
;
911 if (GetGCSet(obj
) != set
) {
912 //debugf("set %d free obj gcset wrong %d %p\n", i, obj->obj_sizeclass, obj);
913 fprintf(stderr
, "set %d free obj gcset wrong %d %p\n", i
, obj
->obj_sizeclass
, obj
);
914 //dumpObject((PyrObject*)obj);
917 if (obj
->next
->prev
!= obj
) {
918 fprintf(stderr
, "set %d free obj->next->prev != obj\n", i
);
919 //dumpObject((PyrObject*)obj);
926 PyrObjectHdr
*grey
= mGrey
.next
;
927 while (!IsMarker(grey
)) {
930 fprintf(stderr
, "sc Object on grey list not grey %d %d %d\n", grey
->gc_color
, mGreyColor
, numgrey
);
931 fprintf(stderr
, "%p <- %p -> %p grey %p process %p\n", mGrey
.prev
, &mGrey
, mGrey
.next
, grey
, mProcess
);
937 if (numgrey
!= mNumGrey
) {
938 fprintf(stderr
, "grey count off %d %d\n", numgrey
, mNumGrey
);
940 fprintf(stderr
, ".");
946 bool PyrGC::LinkSanity()
948 //postfl("PyrGC::LinkSanity\n");
949 for (int i
=0; i
<kNumGCSets
; ++i
) {
950 GCSet
* set
= mSets
+ i
;
953 PyrObjectHdr
* obj
= &set
->mBlack
;
955 if (obj
->next
->prev
!= obj
) {
956 fprintf(stderr
, "set %d black obj->next->prev != obj\n", i
);
957 //dumpObject((PyrObject*)obj);
960 if (obj
->prev
->next
!= obj
) {
961 fprintf(stderr
, "set %d black obj->prev->next != obj\n", i
);
962 //dumpObject((PyrObject*)obj);
966 } while (obj
!= &set
->mBlack
);
971 #define DUMPINSANITY 1
973 bool PyrGC::BlackToWhiteCheck(PyrObject
*objA
)
975 if (objA
->obj_format
> obj_slot
) return true;
977 int size
= objA
->size
;
979 PyrSlot
*slot
= objA
->slots
;
980 for (int j
=size
; j
--; ++slot
) {
981 PyrObject
* objB
= NULL
;
982 if (IsObj(slot
) && slotRawObject(slot
)) {
983 objB
= slotRawObject(slot
);
985 if (objB
&& (unsigned long)objB
< 100) {
986 fprintf(stderr
, "weird obj ptr\n");
993 if (objA
->gc_color
== mBlackColor
&& objA
!= mPartialScanObj
) {
994 if (objB
->gc_color
== mWhiteColor
) {
995 if (objA
->classptr
== class_frame
) {
996 // jmc: black stack frames pointing to white nodes can be ignore
997 PyrFrame
* frameA
= (PyrFrame
*)objA
;
998 PyrMethod
* meth
= slotRawMethod(&frameA
->method
);
999 PyrMethodRaw
* methraw
= METHRAW(meth
);
1000 if (methraw
->needsHeapContext
)
1004 fprintf(stderr
, "black frame to white ref %p %p\n", objA
, objB
);
1005 dumpBadObject(objA
);
1006 dumpBadObject(objB
);
1007 fprintf(stderr
, "\n");
1018 bool PyrGC::SanityMarkObj(PyrObject
*objA
, PyrObject
*fromObj
, int level
)
1020 if (objA
->IsPermanent()) return true;
1021 if (objA
->IsMarked()) return true;
1022 if (objA
->size
> MAXINDEXSIZE(objA
)) {
1023 fprintf(stderr
, "obj indexed size larger than max: %d > %d\n", objA
->size
, MAXINDEXSIZE(objA
));
1024 //dumpObject((PyrObject*)objA);
1028 objA
->SetMark(); // mark it
1029 if (!BlackToWhiteCheck(objA
))
1032 if (objA
->obj_format
<= obj_slot
) {
1034 int size
= objA
->size
;
1036 PyrSlot
*slot
= objA
->slots
;
1037 for (int j
=size
; j
--; ++slot
) {
1038 PyrObject
* objB
= NULL
;
1039 int tag
= GetTag(slot
);
1040 if (tag
== tagObj
&& slotRawObject(slot
))
1041 objB
= slotRawObject(slot
);
1046 fprintf(stderr, "40 levels deep!\n");
1047 dumpBadObject(objA);
1048 dumpBadObject(objB);
1051 bool err
= SanityMarkObj(objB
, objA
, level
+ 1);
1061 bool PyrGC::SanityClearObj(PyrObject
*objA
, int level
)
1063 if (!(objA
->IsMarked())) return true;
1064 if (objA
->IsPermanent()) return true;
1065 objA
->ClearMark(); // unmark it
1067 if (objA
->obj_format
<= obj_slot
) {
1069 int size
= objA
->size
;
1071 PyrSlot
*slot
= objA
->slots
;
1072 for (int j
=size
; j
--; ++slot
) {
1073 PyrObject
*objB
= NULL
;
1074 if (IsObj(slot
) && slotRawObject(slot
)) {
1075 objB
= slotRawObject(slot
);
1079 fprintf(stderr, "40 levels deep!\n");
1080 dumpBadObject(objA);
1081 //dumpObject((PyrObject*)objB); //newPyrFrame
1084 bool err
= SanityClearObj(objB
, level
+1);
1085 if (!err
) return false;
1093 void PyrGC::DumpInfo()
1097 int numblack
, numwhite
, numfree
, settotal
, setsiztotal
;
1098 int totblack
, totgrey
, totwhite
, totfree
, totref
, total
, siztotal
;
1101 post("flips %d collects %d nalloc %d alloc %d grey %d\n", mFlips
, mCollects
, mNumAllocs
, mAllocTotal
, mNumGrey
);
1110 for (i
=0; i
<kNumGCSizeClasses
; ++i
) {
1111 GCSet
*set
= mSets
+ i
;
1115 obj
= set
->mBlack
.next
;
1116 while (!IsMarker(obj
)) {
1123 obj
= set
->mWhite
.next
;
1124 while (obj
!= set
->mFree
) {
1132 while (!IsMarker(obj
)) {
1136 settotal
= numblack
+ numwhite
+ numfree
;
1137 setsiztotal
= settotal
<< (i
+ 3);
1138 siztotal
+= setsiztotal
;
1139 totblack
+= numblack
;
1140 totwhite
+= numwhite
;
1144 post("%2d bwf t sz: %6d %6d %6d %6d %8d\n", i
,
1145 numblack
, numwhite
, numfree
, settotal
, setsiztotal
);
1148 post("tot bwf t sz: %6d %6d %6d %6d %8d\n",
1149 totblack
, totwhite
, totfree
, total
, siztotal
);
1152 void PyrGC::DumpGrey()
1156 PyrObjectHdr
*obj
= mGrey
.next
;
1157 while (!IsMarker(obj
)) {
1158 post("grey %s %d %d\n", slotRawSymbol(&obj
->classptr
->name
)->name
, obj
->obj_sizeclass
, obj
->size
);
1163 void PyrGC::DumpSet(int i
)
1165 GCSet
*set
= mSets
+ i
;
1168 PyrObjectHdr
*obj
= set
->mBlack
.next
;
1169 while (!IsMarker(obj
)) {
1170 post("black %s %d %d\n", slotRawSymbol(&obj
->classptr
->name
)->name
, obj
->obj_sizeclass
, obj
->size
);
1175 obj
= set
->mWhite
.next
;
1176 while (obj
!= set
->mFree
) {
1177 post("white %s %d %d\n", slotRawSymbol(&obj
->classptr
->name
)->name
, obj
->obj_sizeclass
, obj
->size
);
1183 while (!IsMarker(obj
)) {
1184 post("free %s %d %d\n", slotRawSymbol(&obj
->classptr
->name
)->name
, obj
->obj_sizeclass
, obj
->size
);
1189 void PyrGC::ClearMarks()
1191 for (int i
=0; i
<kNumGCSets
; ++i
) {
1192 GCSet
*set
= mSets
+ i
;
1195 PyrObjectHdr
*obj
= set
->mBlack
.next
;
1196 while (!IsMarker(obj
)) {
1197 obj
->ClearMark(); // unmark it
1203 while (!IsMarker(obj
)) {
1204 obj
->ClearMark(); // unmark it
1209 obj
= set
->mWhite
.next
;
1210 while (obj
!= set
->mFree
) {
1211 obj
->ClearMark(); // unmark it
1217 while (!IsMarker(obj
)) {
1218 obj
->ClearMark(); // unmark it
1224 void PyrGC::throwMemfailed(size_t inNumBytes
)
1226 post("alloc failed. size = %d\n", inNumBytes
);