home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / mac / MacMemoryAllocator / src / fastmem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  56.7 KB  |  1,914 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include <Memory.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <stdio.h>
  23. #include "fastmem.h"
  24. #include "prmacos.h"
  25. #include <OSUtils.h>
  26. #include <Processes.h>
  27.  
  28. //##############################################################################
  29. //##############################################################################
  30. #pragma mark malloc DEBUG DECLARATIONS
  31.  
  32. #if STATS_MAC_MEMORY
  33. UInt32 gSmallAllocationTotalCountTable[1025];
  34. UInt32 gSmallAllocationActiveCountTable[1025];
  35. UInt32 gSmallAllocationMaxCountTable[1025];
  36. #endif
  37.  
  38. #if DEBUG_MAC_MEMORY
  39.  
  40. enum {
  41.     kActiveSiteHashTableSize        = 128,
  42.     kActiveSizeListSize                = 1024
  43. };
  44.  
  45. enum {
  46.     kFreeBlockHeaderTag        = 'FREE',
  47.     kFreeBlockTrailerTag    = 'free',
  48.     kUsedBlockHeaderTag        = 'USED',
  49.     kUsedBlockTrailerTag    = 'used',
  50.     kRefdBlockHeaderTag        = 'REFD',
  51.     kRefdBlockTrailerTag    = 'refd',
  52.     kFreeMemoryFillPattern     = 0xEF,
  53.     kUsedMemoryFillPattern    = 0xDB
  54. };
  55.  
  56. MemoryBlockHeader            *gFirstAllocatedBlock = NULL;
  57. MemoryBlockHeader            *gLastAllocatedBlock = NULL;
  58.  
  59. enum {
  60.     kAllocationSiteMalloc            = 0,
  61.     kAllocationSiteNewHandle        = 1,
  62.     kAllocationSiteNewPtr            = 2
  63. };
  64.  
  65. typedef struct AllocationSite AllocationSite;
  66.  
  67. struct AllocationSite {
  68.     UInt32                            type;
  69.     AllocationSite                    *next;
  70.     void                            *whoAllocated[kRecordingDepthOfStackLevels];
  71.     UInt32                            mallocs;
  72.     UInt32                            frees;
  73.     UInt32                            totalAllocations;
  74. };
  75.  
  76. AllocationSite        *gActiveSizeHashTable[kActiveSiteHashTableSize];
  77. AllocationSite        gActiveSizeList[kActiveSizeListSize];
  78. AllocationSite        *gCurrentActiveSize = gActiveSizeList;
  79. UInt32                gRemainingSitesInList = kActiveSizeListSize;
  80.  
  81. AllocationSite *AddAllocationSite(UInt32 allocationType, void **allocatorStack);
  82. void AddBlockToActiveList(void *newBlock, AllocationSite *alocationSite);
  83. void RemoveBlockFromActiveList(void *deadBlock);
  84.  
  85. UInt32                gOutstandingPointers = 0;
  86. UInt32                gOutstandingHandles = 0;
  87.  
  88. #endif
  89.  
  90. //##############################################################################
  91. //##############################################################################
  92. #pragma mark -
  93. #pragma mark malloc DEBUG CONTROL VARIABLES
  94.  
  95. #if DEBUG_MAC_MEMORY
  96.  
  97. UInt32                        gVerifyHeapOnEveryMalloc            = 0;
  98. UInt32                        gVerifyHeapOnEveryFree                = 0;
  99. UInt32                        gFillUsedBlocksWithPattern            = 0;
  100. UInt32                        gFillFreeBlocksWithPattern            = 1;
  101. UInt32                        gTrackLeaks                            = 0;
  102. UInt32                        gDontActuallyFreeMemory                = 0;
  103. UInt32                        gOnMallocFailureReturnDEADBEEF        = 0;
  104. SInt32                        gFailToAllocateAfterNMallocs        = -1;
  105.  
  106. SInt32                        gReportActiveBlocks                    = 1;
  107. SInt32                        gTagReferencedBlocks                = 0;            // for best effect, turn on gFillFreeBlocksWithPattern also
  108. SInt32                        gReportLeaks                        = 1;
  109.  
  110. #endif
  111.  
  112. //##############################################################################
  113. //##############################################################################
  114.  
  115. #if STATS_MAC_MEMORY
  116.  
  117. UInt32        gTotalFixedSizeCompactBlocksAllocated = 0;
  118. UInt32        gTotalFixedSizeCompactBlocksUsed = 0;
  119. UInt32        gTotalFixedSizeCompactAllocated = 0;
  120. UInt32        gTotalFixedSizeCompactUsed = 0;
  121.  
  122. UInt32        gTotalFixedSizeFastBlocksAllocated = 0;
  123. UInt32        gTotalFixedSizeFastBlocksUsed = 0;
  124. UInt32        gTotalFixedSizeFastAllocated = 0;
  125. UInt32        gTotalFixedSizeFastUsed = 0;
  126.  
  127. UInt32        gTotalSmallHeapBlocksAllocated = 0;
  128. UInt32        gTotalSmallHeapBlocksUsed = 0;
  129. UInt32        gTotalSmallHeapAllocated = 0;
  130. UInt32        gTotalSmallHeapUsed = 0;
  131.  
  132.  
  133. //##############################################################################
  134. //##############################################################################
  135. #pragma mark -
  136. #pragma mark DEBUG malloc AND free
  137.  
  138. #endif
  139.  
  140. #if DEBUG_MAC_MEMORY || STATS_MAC_MEMORY
  141.  
  142. void        *gOurApplicationHeapBase;
  143. void        *gOurApplicationHeapMax;
  144.  
  145. #if GENERATINGPOWERPC
  146. asm void *GetCurrentStackPointer() 
  147. {
  148.     mr        r3, sp
  149.     lwz        r3, 0(r3)
  150.     blr
  151. }
  152. #endif
  153.  
  154. UInt32        gNextBlockNum = 0;
  155.  
  156. void *malloc(size_t blockSize)
  157. {
  158.     MemoryBlockHeader        *newBlockHeader;
  159. #if DEBUG_MAC_MEMORY
  160.     MemoryBlockTrailer        *newBlockTrailer;    
  161. #endif
  162.     size_t                    newCompositeSize = blockSize + sizeof(MemoryBlockHeader) + MEMORY_BLOCK_TAILER_SIZE;
  163.     size_t                    blockSizeCopy = blockSize;
  164.     UInt32                    stackIterator;
  165.     void                    *newBlock;
  166.     void                    *currentSP;
  167.  
  168. #if DEBUG_MAC_MEMORY
  169.  
  170. #if GENERATINGPOWERPC
  171.     currentSP = GetCurrentStackPointer();
  172. #endif
  173.  
  174.     if (gVerifyHeapOnEveryMalloc)
  175.         VerifyMallocHeapIntegrity();
  176.         
  177.     if (gFailToAllocateAfterNMallocs != -1) {
  178.         if (gFailToAllocateAfterNMallocs-- == 0)
  179.             return NULL;
  180.     }
  181. #endif
  182.  
  183. #if STATS_MAC_MEMORY
  184.  
  185.     if (blockSizeCopy >= 1024)
  186.         blockSizeCopy = 1024;
  187.  
  188.     gSmallAllocationTotalCountTable[blockSizeCopy]++;
  189.     gSmallAllocationActiveCountTable[blockSizeCopy]++;
  190.     if (gSmallAllocationActiveCountTable[blockSizeCopy] > gSmallAllocationMaxCountTable[blockSizeCopy])
  191.         gSmallAllocationMaxCountTable[blockSizeCopy] = gSmallAllocationActiveCountTable[blockSizeCopy];
  192.  
  193. #endif
  194.  
  195.     if (blockSize <= kMaxTableAllocatedBlockSize) {
  196.         AllocMemoryBlockDescriptor    *whichAllocator;
  197.         whichAllocator = gFastMemSmallSizeAllocators + ((blockSize + 3) >> 2);
  198.         newBlock = (char *)(whichAllocator->allocRoutine)(blockSize, whichAllocator->refcon) - sizeof(MemoryBlockHeader);
  199.     }
  200.     
  201.     else {
  202.         newBlock =  (char *)StandardAlloc(blockSize, 0) - sizeof(MemoryBlockHeader);
  203.     }
  204.  
  205. #if DEBUG_MAC_MEMORY
  206.     if (((Ptr)newBlock + sizeof(MemoryBlockHeader)) == NULL) {
  207.         DebugStr("\pMALLOC FALUIRE");
  208.         if (gOnMallocFailureReturnDEADBEEF)
  209.             return (void *)0xDEADBEEF;
  210.         else
  211.             return NULL;
  212.     }
  213.  
  214.     //    Fill in the blocks header.  This includes adding the 
  215.     //    block to the used list.
  216.     
  217.     newBlockHeader = (MemoryBlockHeader *)newBlock;
  218.  
  219.     memset(newBlockHeader->whoAllocated, 0, sizeof(void *) * kRecordingDepthOfStackLevels);
  220.  
  221. #if GENERATINGPOWERPC
  222.     for (stackIterator = 0; stackIterator < kRecordingDepthOfStackLevels; stackIterator++) {
  223.         if ((currentSP < gOurApplicationHeapBase) || (currentSP > gOurApplicationHeapMax))
  224.             break;
  225.         newBlockHeader->whoAllocated[stackIterator] = *((void **)((char *)currentSP + 8));
  226.         currentSP = *((void **)currentSP);
  227.     }
  228. #endif
  229.  
  230.     newBlockHeader->blockSize = blockSize;
  231.     newBlockHeader->headerTag = kUsedBlockHeaderTag;
  232.     newBlockHeader->blockNum = ++gNextBlockNum;
  233.     
  234.     newBlockHeader->next = gFirstAllocatedBlock;
  235.     newBlockHeader->prev = NULL;    
  236.  
  237.     if (gFirstAllocatedBlock != NULL)
  238.         gFirstAllocatedBlock->prev = newBlockHeader;
  239.     else
  240.         gLastAllocatedBlock = newBlockHeader;
  241.     gFirstAllocatedBlock = newBlockHeader;
  242.     
  243.     //    Fill in the trailer
  244.     
  245.     newBlockTrailer = (MemoryBlockTrailer *)((char *)newBlock + newCompositeSize - sizeof(MemoryBlockTrailer));
  246.     newBlockTrailer->trailerTag = kUsedBlockTrailerTag;
  247.     
  248.     //    Fill with the used memory pattern
  249.     
  250.     if (gFillUsedBlocksWithPattern)
  251.         memset((char *)newBlock + sizeof(MemoryBlockHeader), kUsedMemoryFillPattern, blockSize);
  252.  
  253.     //    If leak detection is on, then add this block to the 
  254.     //    tracking list.
  255.     
  256.     if (gTrackLeaks)
  257.         AddAllocationSite(kAllocationSiteMalloc, newBlockHeader->whoAllocated);
  258.     
  259. #endif
  260.  
  261.     return (void *)((char *)newBlock + sizeof(MemoryBlockHeader));
  262.     
  263. }
  264.  
  265. void free(void *deadBlock)
  266. {
  267.     MemoryBlockHeader            *deadBlockHeader;
  268. #if DEBUG_MAC_MEMORY
  269.     MemoryBlockTrailer            *deadBlockTrailer;
  270. #endif
  271.     size_t                        deadBlockSize;    
  272.     char                        *deadBlockBase;
  273.     FreeMemoryBlockDescriptor    *descriptor;
  274.     
  275. #if DEBUG_MAC_MEMORY
  276.     if (gVerifyHeapOnEveryFree)
  277.         VerifyMallocHeapIntegrity();
  278. #endif
  279.         
  280.     if (deadBlock == NULL)
  281.         return;
  282.     
  283.     deadBlockBase = ((char *)deadBlock - sizeof(MemoryBlockHeader));
  284.  
  285.     deadBlockHeader = (MemoryBlockHeader *)deadBlockBase;
  286.     deadBlockSize = deadBlockHeader->blockSize;
  287.  
  288. #if DEBUG_MAC_MEMORY
  289.     deadBlockTrailer = (MemoryBlockTrailer *)(deadBlockBase + deadBlockSize + sizeof(MemoryBlockHeader));
  290. #endif
  291.     
  292. #if STATS_MAC_MEMORY
  293.     if (deadBlockSize >= 1024)
  294.         deadBlockSize = 1024;
  295.     gSmallAllocationActiveCountTable[deadBlockSize]--;
  296. #endif
  297.     
  298. #if DEBUG_MAC_MEMORY
  299.     if (deadBlockHeader->headerTag == kFreeBlockHeaderTag)
  300.         DebugStr("\pfastmem: double dispose of malloc block");
  301.     else
  302.         if ((deadBlockHeader->headerTag != kUsedBlockHeaderTag) || (deadBlockTrailer->trailerTag != kUsedBlockTrailerTag))
  303.             DebugStr("\pfastmem: attempt to dispose illegal block");
  304.     
  305.     //    Remove the block from the list of used blocks.
  306.     
  307.     if (deadBlockHeader->next != NULL)
  308.         deadBlockHeader->next->prev = deadBlockHeader->prev;
  309.     else
  310.         gLastAllocatedBlock = deadBlockHeader->prev;
  311.         
  312.     if (deadBlockHeader->prev != NULL)
  313.         deadBlockHeader->prev->next = deadBlockHeader->next;
  314.     else
  315.         gFirstAllocatedBlock = deadBlockHeader->next;
  316.     
  317.     //    Change the header and tailer tags to be the free ones.
  318.     
  319.     deadBlockHeader->headerTag = kFreeBlockHeaderTag;
  320.     deadBlockTrailer->trailerTag = kFreeBlockTrailerTag;
  321.  
  322.     //    If we are tracking leaks, then decrement this blocks
  323.     //    usage in the tracking table.
  324.     
  325.     if (gTrackLeaks) {
  326.  
  327.         UInt32                hashBin = ((UInt32)(deadBlockHeader->whoAllocated[0]) >> 2) % kActiveSiteHashTableSize;
  328.         AllocationSite        *currentSite = gActiveSizeHashTable[hashBin];
  329.         
  330.         while (currentSite) {
  331.             UInt32    currentStackLevel;
  332.             for (currentStackLevel = 0; currentStackLevel < kRecordingDepthOfStackLevels; currentStackLevel++) {
  333.                 if (currentSite->whoAllocated[currentStackLevel] != deadBlockHeader->whoAllocated[currentStackLevel])
  334.                     break;
  335.             }
  336.             if (currentStackLevel == kRecordingDepthOfStackLevels)
  337.                 break;
  338.             currentSite = currentSite->next;
  339.         }
  340.         
  341.         if (currentSite != NULL)
  342.             currentSite->frees++;
  343.  
  344.     }
  345.  
  346.     //    Fill with the free memory pattern
  347.     
  348.     if (gFillFreeBlocksWithPattern)
  349.         memset(deadBlock, kFreeMemoryFillPattern, deadBlockSize);
  350.  
  351.     if (!gDontActuallyFreeMemory) {
  352.         descriptor = deadBlockHeader->blockFreeRoutine;
  353.         (descriptor->freeRoutine)(deadBlock, descriptor->refcon);
  354.     }
  355.     
  356. #endif
  357.     
  358. }
  359.  
  360. #else
  361.  
  362. //##############################################################################
  363. //##############################################################################
  364. #pragma mark -
  365. #pragma mark OPTIMIZED POWERPC malloc AND free
  366.  
  367. #if (defined(powerc) || defined(_powerc))
  368.  
  369. void *malloc(size_t blockSize)
  370. {
  371.     return AsmMalloc(blockSize);
  372. }
  373.  
  374.  
  375. asm void *AsmMalloc(size_t blockSize)
  376. {
  377.     cmplwi    r3, kMaxTableAllocatedBlockSize
  378.     bgt        largeAlloc
  379.     
  380.     lwz        r6,gFastMemSmallSizeAllocators(RTOC)
  381.     addi    r4,r3,3
  382.     rlwinm    r4,r4,1,0,28
  383.     add     r6,r6,r4
  384.     
  385.     lwz        r5,0(r6)
  386.     lwz        r5,0(r5)
  387.     mtctr    r5
  388.     lwz        r4,4(r6)
  389.  
  390.     bcctr    31, 0
  391.  
  392. largeAlloc:
  393.  
  394.     b        StandardAlloc
  395. }
  396.  
  397.  
  398. void free(void *block)
  399. {
  400.     AsmFree(block);
  401. }
  402.  
  403.  
  404. asm void AsmFree(void *)
  405. {
  406.     cmplwi    r3, 0
  407.     beqlr
  408.     
  409.     subi    r5,r3,4
  410.     lwz        r5,0(r5)
  411.     lwz        r6,0(r5)
  412.     lwz        r6,0(r6)
  413.     mtctr    r6
  414.     lwz        r4,4(r5)
  415.     bcctr    31, 0
  416. }
  417.  
  418. #else
  419.  
  420. //##############################################################################
  421. //##############################################################################
  422. #pragma mark -
  423. #pragma mark STANDARD malloc AND free
  424.  
  425. void *malloc(size_t blockSize)
  426. {
  427.  
  428.     if (blockSize <= kMaxTableAllocatedBlockSize) {
  429.         AllocMemoryBlockDescriptor    *whichAllocator;
  430.         whichAllocator = gFastMemSmallSizeAllocators + ((blockSize + 3) >> 2);
  431.         return (whichAllocator->allocRoutine)(blockSize, whichAllocator->refcon);
  432.     }
  433.     
  434.     else {
  435.         return StandardAlloc(blockSize, 0);
  436.     }
  437.     
  438. }
  439.  
  440. void free(void *block)
  441. {
  442.     MemoryBlockHeader            *blockHeader;
  443.     FreeMemoryBlockDescriptor    *descriptor;
  444.     if (block != NULL) {
  445.         blockHeader = (MemoryBlockHeader *)((char *)block - sizeof(MemoryBlockHeader));
  446.         descriptor = blockHeader->blockFreeRoutine;
  447.         (descriptor->freeRoutine)(block, descriptor->refcon);
  448.     }
  449. }
  450.  
  451.  
  452. #endif
  453.  
  454. #endif
  455.  
  456. //##############################################################################
  457. //##############################################################################
  458. #pragma mark -
  459. #pragma mark realloc AND calloc
  460.  
  461. void* reallocSmaller(void* block, size_t newSize)
  462. {
  463. //    This actually doesn't reclaim memory!
  464. #if 0
  465.     MemoryBlockHeader            *blockHeader;
  466. #if DEBUG_MAC_MEMORY
  467.     MemoryBlockTrailer            *blockTrailer;
  468. #endif
  469.     if (block != NULL) {
  470.         blockHeader = (MemoryBlockHeader *)((char *)block - sizeof(MemoryBlockHeader));
  471.         if (blockHeader->blockFreeRoutine->freeRoutine == &StandardFree) { 
  472.             size_t        newCompositeSize = newSize + sizeof(MemoryBlockHeader) + MEMORY_BLOCK_TAILER_SIZE;
  473.             newCompositeSize = (newCompositeSize + 3) & 0xFFFFFFFC;
  474.             SetPtrSize((Ptr)blockHeader, newCompositeSize);
  475. #if DEBUG_MAC_MEMORY
  476.             blockHeader->blockSize = newSize;
  477.             blockTrailer = (MemoryBlockTrailer *)((char *)block + newSize + sizeof(MemoryBlockHeader));
  478.             blockTrailer->trailerTag = kUsedBlockTrailerTag;
  479. #endif
  480.         }
  481.     }
  482. #endif
  483. }
  484.  
  485. void* realloc(void* block, size_t newSize)
  486. {
  487.     void         *newBlock = NULL;    
  488.     UInt8        tryAgain = true;
  489.     
  490.     newBlock = malloc(newSize);
  491.     
  492.     if (newBlock != NULL) {    
  493.         BlockMoveData(block, newBlock, newSize);
  494.         free(block);
  495.     }
  496.  
  497.     return newBlock;
  498. }
  499.  
  500. void *calloc(size_t nele, size_t elesize)
  501. {
  502.     char         *newBlock = NULL;
  503.     UInt8        tryAgain = true;
  504.     size_t        totalSize = nele * elesize;
  505.  
  506.     newBlock = (char *)malloc(totalSize);
  507.  
  508.     if (newBlock != NULL)
  509.         memset(newBlock, 0, totalSize);
  510.  
  511.     return newBlock;
  512. }
  513.  
  514.  
  515. //##############################################################################
  516. //##############################################################################
  517. #pragma mark -
  518. #pragma mark DEBUG MEMORY UTILS
  519.  
  520. #if STATS_MAC_MEMORY
  521.  
  522. FILE     *statsFile = NULL;
  523.  
  524. void DumpCurrentMemoryStatistics(char *operation)
  525. {
  526.     UInt32    count;
  527.     
  528.     if (statsFile == NULL)
  529.         statsFile = fopen("stats", "w");
  530.     
  531.     fprintf(statsFile, "%s\n", operation);
  532.     fprintf(statsFile, "Total Allocations\n");
  533.  
  534.     for (count = 0; count < 1025; count++)
  535.         fprintf(statsFile, "%ld\n", gSmallAllocationTotalCountTable[count]);
  536.  
  537.     fprintf(statsFile, "Current Allocation Allocations\n");
  538.  
  539.     for (count = 0; count < 1025; count++)
  540.         fprintf(statsFile, "%ld\n", gSmallAllocationActiveCountTable[count]);
  541.  
  542. }
  543.  
  544. #endif
  545.  
  546. #if DEBUG_MAC_MEMORY || STATS_MAC_MEMORY
  547.  
  548. void PrintHexNumber(UInt32 hexNumber)
  549. {
  550.     char        hexString[11];
  551.     char        hexMap[] = "0123456789ABCDEF";
  552.     long        digits = 8;
  553.         
  554.     
  555.     hexString[0] = '0';
  556.     hexString[1] = 'x';
  557.     
  558.     while (digits) {
  559.         hexString[digits + 1] = *((hexNumber & 0x0F) + hexMap);
  560.         hexNumber = hexNumber >> 4;
  561.         digits--;
  562.     }
  563.     hexString[10] = 0;
  564.     
  565.     printf(hexString);
  566.     
  567. }
  568.  
  569. #endif
  570.  
  571.  
  572. #if DEBUG_MAC_MEMORY
  573.  
  574. AllocationSite *
  575. AddAllocationSite(UInt32 allocationType, void **allocatorStack)
  576. {
  577.     UInt32                hashBin = ((UInt32)allocatorStack[0] >> 2) % kActiveSiteHashTableSize;
  578.     AllocationSite        *currentSite = gActiveSizeHashTable[hashBin];
  579.     
  580.     while (currentSite) {
  581.         UInt32    currentStackLevel;
  582.         for (currentStackLevel = 0; currentStackLevel < kRecordingDepthOfStackLevels; currentStackLevel++) {
  583.             if (currentSite->whoAllocated[currentStackLevel] != allocatorStack[currentStackLevel])
  584.                 break;
  585.         }
  586.         if (currentStackLevel == kRecordingDepthOfStackLevels)
  587.             break;
  588.         currentSite = currentSite->next;
  589.     }
  590.     
  591.     //    If this is a new site, then create a new entry from the table
  592.     
  593.     if ((currentSite == NULL) && (gRemainingSitesInList != 0)) {
  594.         currentSite = gCurrentActiveSize++;
  595.         gRemainingSitesInList--;
  596.         currentSite->next = gActiveSizeHashTable[hashBin];
  597.         gActiveSizeHashTable[hashBin] = currentSite;
  598.         BlockMoveData(allocatorStack, currentSite->whoAllocated, sizeof(void *) * kRecordingDepthOfStackLevels);
  599.         currentSite->totalAllocations = 0;
  600.         currentSite->mallocs = 0;
  601.         currentSite->frees = 0;
  602.         currentSite->type = allocationType;
  603.     }
  604.  
  605.     if (currentSite != NULL) {
  606.         currentSite->mallocs++;
  607.         currentSite->totalAllocations++;
  608.     }
  609.     
  610.     return currentSite;
  611.     
  612. }
  613.  
  614. extern void VerifyMallocHeapIntegrity()
  615. {
  616.     MemoryBlockHeader    *currentBlock = gFirstAllocatedBlock;
  617.  
  618.     //    Walk the used block list, checking all of the headers.
  619.  
  620.     while (currentBlock != NULL) {
  621.     
  622.         MemoryBlockTrailer    *trailer;
  623.         
  624.         trailer = (MemoryBlockTrailer *)((char *)currentBlock + sizeof(MemoryBlockHeader) + currentBlock->blockSize);
  625.     
  626.         if ((currentBlock->headerTag != kUsedBlockHeaderTag) || (trailer->trailerTag != kUsedBlockTrailerTag))
  627.             DebugStr("\pfastmem: malloc heap is corrupt!");
  628.         
  629.         currentBlock = currentBlock->next;
  630.     
  631.     }
  632.     
  633. }
  634.  
  635. enum {
  636.     kMaxInstructionScanDistance    = 4096
  637. };
  638.  
  639. void PrintRoutineNameFromPC(void *currentPC)
  640. {
  641.     UInt32        instructionsToLook = kMaxInstructionScanDistance;
  642.     UInt32        *currentPCAsLong = (UInt32 *)currentPC;
  643.     UInt32        offset = 0;
  644.     char        labelBuffer[256];
  645.     
  646.     if (currentPC == NULL)
  647.         return;
  648.     
  649.     while (instructionsToLook--) {
  650.     
  651.         if (*currentPCAsLong == 0x4E800020) {
  652.             char    stringLength = *((char *)currentPCAsLong + 21);
  653.             memset(labelBuffer, 0, 256);
  654.             BlockMoveData(((char *)currentPCAsLong + 22), labelBuffer, stringLength);
  655.             printf(labelBuffer);
  656.             break;
  657.         }
  658.     
  659.         currentPCAsLong++;
  660.         
  661.     }
  662.  
  663.     instructionsToLook = kMaxInstructionScanDistance;
  664.     currentPCAsLong = (UInt32 *)currentPC;
  665.  
  666.     while (instructionsToLook--) {
  667.         if (*currentPCAsLong == 0x7C0802A6) {
  668.             printf("+");
  669.             PrintHexNumber(offset - 4);
  670.             break;
  671.         }
  672.         currentPCAsLong--;
  673.         offset += 4;
  674.     }
  675.  
  676. }
  677.  
  678. #endif
  679.  
  680. #if STATS_MAC_MEMORY
  681. void PrintEfficiency(UInt32 current, UInt32 total)
  682. {    
  683.     UInt32     efficiency = current * 1000 / total;
  684.     UInt32    efficiencyLow = efficiency / 10;
  685.     
  686.     efficiency = efficiency/10;
  687.     
  688.     printf("%ld.%ld", efficiency, efficiencyLow);
  689.     
  690. }
  691. #endif
  692.  
  693. #if DEBUG_MAC_MEMORY
  694. static void TagReferencedBlocks(void)
  695. {
  696.     char *start = (char *) ApplicationZone();
  697.     char *end = (char *) GetApplLimit();
  698.     
  699.     char *comb = start;
  700.     
  701.     while (comb < end) {
  702.     
  703.         MemoryBlockHeader *curCandidate = (MemoryBlockHeader *) comb;
  704.         
  705.         if (curCandidate->headerTag == kFreeBlockHeaderTag || 
  706.             curCandidate->headerTag == kUsedBlockHeaderTag ||
  707.             curCandidate->headerTag == kRefdBlockHeaderTag) {
  708.             
  709.             // we are pointing at a block header            
  710.             // we don't want to consider the next or prev structure members
  711.             // therefore, skip ahead 8 bytes = 2 * sizeof(MemoryBlockHeader *)
  712.                         
  713.             comb += 8;
  714.             
  715.         } else if ((char *) curCandidate->next > start &&
  716.                 (char *) curCandidate->next < end) {
  717.                 
  718.             MemoryBlockHeader *referencedBlock;
  719.             referencedBlock = (MemoryBlockHeader *) ((char *) curCandidate->next - sizeof(MemoryBlockHeader));
  720.                 
  721.             if (referencedBlock->headerTag == kUsedBlockHeaderTag) {
  722.                     
  723.                 // Bingo!!
  724.                 // Marked the referenced block as being referenced.
  725.                 // skip ahead 4 bytes    (or should we be conservative and just skip 2 bytes?)
  726.                 
  727.                 referencedBlock->headerTag = kRefdBlockHeaderTag;    // TODO: insert kRefdBlockTrailerTag as well
  728.                 comb += 4;
  729.                 
  730.             } else {
  731.             
  732.                 // False alarm
  733.                 // it looked like a pointer, but it didn't point to the beginning of a valid used block.
  734.                 // move forward two bytes and look some more
  735.                 
  736.                 comb += 2;
  737.             }
  738.                 
  739.         } else {
  740.         
  741.             // we aren't looking at anything interesting
  742.             // move forward two bytes and look some more.
  743.             
  744.             comb += 2;
  745.         }
  746.         
  747.     }
  748.     
  749. }
  750. #endif
  751.  
  752. void DumpAllocHeap(void)
  753. {
  754. #if DEBUG_MAC_MEMORY
  755.     MemoryBlockHeader            *currentBlock = gFirstAllocatedBlock;
  756. #endif
  757.  
  758. #if STATS_MAC_MEMORY
  759.  
  760.     UInt32                        currentItem;
  761.     
  762.     printf("********************************************************************************\n");    
  763.     printf("********************************************************************************\n");    
  764.     printf("USAGE REPORT (MALLOC HEAP)\n");
  765.     printf("********************************************************************************\n");    
  766.     printf("********************************************************************************\n");
  767.     printf("TYPE      BLOCKS (A)  BLOCKS (U)  BLOCKS (F)  MEMORY (A)  MEMORY (U)  EFFICIENCY\n");
  768.     printf("----      ----------  ----------  ----------  ----------  ----------  ----------\n");
  769.     printf("COMPACT   ");
  770.     PrintHexNumber(gTotalFixedSizeCompactBlocksAllocated);
  771.     printf("  ");    
  772.     PrintHexNumber(gTotalFixedSizeCompactBlocksUsed);
  773.     printf("  ");    
  774.     PrintHexNumber(gTotalFixedSizeCompactBlocksAllocated - gTotalFixedSizeCompactBlocksUsed);
  775.     printf("  ");    
  776.     PrintHexNumber(gTotalFixedSizeCompactAllocated);
  777.     printf("  ");    
  778.     PrintHexNumber(gTotalFixedSizeCompactUsed);
  779.     printf("  ");
  780.     PrintEfficiency(gTotalFixedSizeCompactBlocksUsed, gTotalFixedSizeCompactBlocksAllocated);
  781.     printf("/");
  782.     PrintEfficiency(gTotalFixedSizeCompactUsed, gTotalFixedSizeCompactAllocated);
  783.     printf("  \n");    
  784.     printf("FIXED     ");
  785.     PrintHexNumber(gTotalFixedSizeFastBlocksAllocated);
  786.     printf("  ");    
  787.     PrintHexNumber(gTotalFixedSizeFastBlocksUsed);
  788.     printf("  ");    
  789.     PrintHexNumber(gTotalFixedSizeFastBlocksAllocated - gTotalFixedSizeFastBlocksUsed);
  790.     printf("  ");    
  791.     PrintHexNumber(gTotalFixedSizeFastAllocated);
  792.     printf("  ");    
  793.     PrintHexNumber(gTotalFixedSizeFastUsed);
  794.     printf("  ");
  795.     PrintEfficiency(gTotalFixedSizeFastBlocksUsed, gTotalFixedSizeFastBlocksAllocated);
  796.     printf("/");
  797.     PrintEfficiency(gTotalFixedSizeFastUsed, gTotalFixedSizeFastAllocated);
  798.     printf("  \n");    
  799.     printf("HEAP      ");
  800.     PrintHexNumber(0);
  801.     printf("  ");    
  802.     PrintHexNumber(gTotalSmallHeapBlocksUsed);
  803.     printf("  ");    
  804.     PrintHexNumber(0);
  805.     printf("  ");    
  806.     PrintHexNumber(gTotalSmallHeapAllocated);
  807.     printf("  ");    
  808.     PrintHexNumber(gTotalSmallHeapUsed);
  809.     printf("  ");
  810.     PrintEfficiency(gTotalSmallHeapUsed, gTotalSmallHeapAllocated);
  811.     printf("  \nTotal efficiency: ");
  812.     PrintEfficiency(gTotalSmallHeapUsed + gTotalFixedSizeFastUsed + gTotalFixedSizeCompactUsed, 
  813.         gTotalSmallHeapAllocated + gTotalFixedSizeFastAllocated + gTotalFixedSizeCompactAllocated);
  814.     printf("  \n");    
  815.     printf("********************************************************************************\n");    
  816.     printf("********************************************************************************\n");    
  817.     printf("BLOCK DISTRIBUTION (MALLOC HEAP: ACTIVE)\n");
  818.     printf("********************************************************************************\n");    
  819.     printf("********************************************************************************\n");
  820.     printf("SIZE      +0x00       +0x01       +0x02      +0x03        TOTAL\n");
  821.     printf("----      ----------  ----------  ----------  ----------  ----------\n");
  822.     
  823.     for (currentItem = 0; currentItem < 64; currentItem++) {
  824.         PrintHexNumber(currentItem * 4);
  825.         printf("  ");    
  826.         PrintHexNumber(gSmallAllocationActiveCountTable[currentItem * 4]);
  827.         printf("  ");    
  828.         PrintHexNumber(gSmallAllocationActiveCountTable[currentItem * 4 + 1]);
  829.         printf("  ");    
  830.         PrintHexNumber(gSmallAllocationActiveCountTable[currentItem * 4 + 2]);
  831.         printf("  ");    
  832.         PrintHexNumber(gSmallAllocationActiveCountTable[currentItem * 4 + 3]);
  833.         printf("  ");    
  834.         PrintHexNumber(gSmallAllocationActiveCountTable[currentItem * 4] + 
  835.             gSmallAllocationActiveCountTable[currentItem * 4 + 1] +
  836.             gSmallAllocationActiveCountTable[currentItem * 4 + 2] +
  837.             gSmallAllocationActiveCountTable[currentItem * 4 + 3]);
  838.         printf("\n");    
  839.     }
  840.     printf("Blocks Over 1K:");
  841.     PrintHexNumber(gSmallAllocationActiveCountTable[1024]);
  842.     printf("\n");    
  843.     printf("********************************************************************************\n");    
  844.     printf("********************************************************************************\n");    
  845.     printf("BLOCK DISTRIBUTION (MALLOC HEAP: MAX)\n");
  846.     printf("********************************************************************************\n");    
  847.     printf("********************************************************************************\n");
  848.     printf("SIZE      +0x00       +0x01       +0x02      +0x03        TOTAL\n");
  849.     printf("----      ----------  ----------  ----------  ----------  ----------\n");
  850.     
  851.     for (currentItem = 0; currentItem < 64; currentItem++) {
  852.         PrintHexNumber(currentItem * 4);
  853.         printf("  ");    
  854.         PrintHexNumber(gSmallAllocationMaxCountTable[currentItem * 4]);
  855.         printf("  ");    
  856.         PrintHexNumber(gSmallAllocationMaxCountTable[currentItem * 4 + 1]);
  857.         printf("  ");    
  858.         PrintHexNumber(gSmallAllocationMaxCountTable[currentItem * 4 + 2]);
  859.         printf("  ");    
  860.         PrintHexNumber(gSmallAllocationMaxCountTable[currentItem * 4 + 3]);
  861.         printf("  ");    
  862.         PrintHexNumber(gSmallAllocationMaxCountTable[currentItem * 4] + 
  863.             gSmallAllocationMaxCountTable[currentItem * 4 + 1] +
  864.             gSmallAllocationMaxCountTable[currentItem * 4 + 2] +
  865.             gSmallAllocationMaxCountTable[currentItem * 4 + 3]);
  866.         printf("\n");    
  867.     }
  868.     printf("Blocks Over 1K:");
  869.     PrintHexNumber(gSmallAllocationMaxCountTable[1024]);
  870.     printf("\n");    
  871.     printf("********************************************************************************\n");    
  872.     printf("********************************************************************************\n");    
  873.     printf("BLOCK DISTRIBUTION (MALLOC HEAP: TOTAL)\n");
  874.     printf("********************************************************************************\n");    
  875.     printf("********************************************************************************\n");
  876.     printf("SIZE        +0x00       +0x01       +0x02      +0x03        TOTAL\n");
  877.     printf("----        ----------  ----------  ----------  ----------  ----------\n");
  878.     
  879.     for (currentItem = 0; currentItem < 64; currentItem++) {
  880.         PrintHexNumber(currentItem * 4);
  881.         printf("  ");    
  882.         PrintHexNumber(gSmallAllocationTotalCountTable[currentItem * 4]);
  883.         printf("  ");    
  884.         PrintHexNumber(gSmallAllocationTotalCountTable[currentItem * 4 + 1]);
  885.         printf("  ");    
  886.         PrintHexNumber(gSmallAllocationTotalCountTable[currentItem * 4 + 2]);
  887.         printf("  ");    
  888.         PrintHexNumber(gSmallAllocationTotalCountTable[currentItem * 4 + 3]);
  889.         printf("  ");    
  890.         PrintHexNumber(gSmallAllocationTotalCountTable[currentItem * 4] + 
  891.             gSmallAllocationTotalCountTable[currentItem * 4 + 1] +
  892.             gSmallAllocationTotalCountTable[currentItem * 4 + 2] +
  893.             gSmallAllocationTotalCountTable[currentItem * 4 + 3]);
  894.         printf("\n");    
  895.     }
  896.     printf("Blocks Over 1K:");
  897.     PrintHexNumber(gSmallAllocationTotalCountTable[1024]);
  898.     printf("\n");    
  899.  
  900. #endif
  901.     
  902. #if DEBUG_MAC_MEMORY
  903.  
  904.     currentBlock = gFirstAllocatedBlock;
  905.  
  906.     //    Report leaks
  907.     
  908.     if (gReportLeaks) {
  909.     
  910.         AllocationSite    *scanSite = gActiveSizeList;
  911.         
  912.         printf("********************************************************************************\n");    
  913.         printf("********************************************************************************\n");    
  914.         printf("LEAKS\n");
  915.         printf("********************************************************************************\n");    
  916.         printf("********************************************************************************\n");
  917.         printf("TYPE    ALLOCS      FREES       LEAKS       STACK\n");
  918.         printf("------  ------      -----       -----       -----\n");
  919.         
  920.         while (scanSite != gCurrentActiveSize) {
  921.             
  922.             if (scanSite->mallocs > (scanSite->frees + 1)) {
  923.         
  924.                 UInt32    currentStackLevel;
  925.             
  926.                 switch (scanSite->type) {
  927.                     case kAllocationSiteMalloc:
  928.                         printf("MALLOC  ");
  929.                         break;    
  930.                     case kAllocationSiteNewHandle:
  931.                         printf("HANDLE  ");
  932.                         break;    
  933.                     case kAllocationSiteNewPtr:
  934.                         printf("POINTR  ");
  935.                         break;    
  936.                     default:
  937.                         break;    
  938.                 }
  939.             
  940.                 PrintHexNumber(scanSite->mallocs);
  941.                 printf("\t");    
  942.                 PrintHexNumber(scanSite->frees);
  943.                 printf("\t");    
  944.                 PrintHexNumber(scanSite->totalAllocations - scanSite->frees);
  945.                 printf("\t");    
  946.  
  947.                 for (currentStackLevel = 0; currentStackLevel < kRecordingDepthOfStackLevels; currentStackLevel++) {
  948.                     PrintRoutineNameFromPC(scanSite->whoAllocated[currentStackLevel]);
  949.                     if (currentStackLevel == kRecordingDepthOfStackLevels - 1)
  950.                         printf("\n");
  951.                     else
  952.                         printf(",");
  953.                 }
  954.                 
  955.             }
  956.             
  957.             scanSite++;
  958.             
  959.         }    
  960.         
  961.         printf("Outstanding Pointers:");
  962.         PrintHexNumber(gOutstandingPointers);
  963.         printf("\n");    
  964.  
  965.         printf("Outstanding Handles:");
  966.         PrintHexNumber(gOutstandingHandles);
  967.         printf("\n");    
  968.  
  969.     }
  970.     
  971.     // Tag blocks which are referenced from somewhere in the heap.
  972.     
  973.     if (gTagReferencedBlocks) {
  974.         TagReferencedBlocks();
  975.     }
  976.  
  977.     //    Dump out active blocks
  978.     
  979.     if (gReportActiveBlocks) {
  980.     
  981.         printf("********************************************************************************\n");    
  982.         printf("********************************************************************************\n");    
  983.         printf("ACTIVE BLOCKS\n");
  984.         printf("********************************************************************************\n");    
  985.         printf("********************************************************************************\n");
  986.         printf("ADDRESS     NUMBER      SIZE        STACK\n");
  987.         printf("-------     ------      ----        -----\n");
  988.         
  989.         while (currentBlock) {
  990.         
  991.             UInt32     currentStackLevel;
  992.  
  993.             if (!gTagReferencedBlocks || currentBlock->headerTag == kUsedBlockHeaderTag) {
  994.                 PrintHexNumber((UInt32)currentBlock);
  995.                 printf("\t");    
  996.                 PrintHexNumber((UInt32)(currentBlock->blockNum));
  997.                 printf("\t");    
  998.                 PrintHexNumber((UInt32)(currentBlock->blockSize));
  999.                 printf("\t");
  1000.  
  1001.                 for (currentStackLevel = 0; currentStackLevel < kRecordingDepthOfStackLevels; currentStackLevel++) {
  1002.                     PrintRoutineNameFromPC(currentBlock->whoAllocated[currentStackLevel]);
  1003.                     if (currentStackLevel == kRecordingDepthOfStackLevels - 1)
  1004.                         printf("\n");
  1005.                     else
  1006.                         printf(",");
  1007.                 }
  1008.             }
  1009.  
  1010.             currentBlock = currentBlock->next;
  1011.  
  1012.         }    
  1013.  
  1014.     }
  1015.  
  1016. #endif
  1017.  
  1018. }
  1019.  
  1020. FreeMemoryBlockDescriptor    StandardFreeDescriptor = { &StandardFree, 0 };
  1021.  
  1022. //##############################################################################
  1023. //##############################################################################
  1024. #pragma mark -
  1025. #pragma mark STANDARD ALLOCATOR (SLOW!)
  1026.  
  1027. void *StandardAlloc(size_t blockSize, void *refcon)
  1028. {
  1029.     MemoryBlockHeader    *newBlockHeader = (MemoryBlockHeader*)AllocateRawMemory(((blockSize + 3) & 0xFFFFFFFC) + sizeof(MemoryBlockHeader) + MEMORY_BLOCK_TAILER_SIZE);
  1030.     if (newBlockHeader == NULL)
  1031.         return NULL;
  1032.     newBlockHeader->blockFreeRoutine = &StandardFreeDescriptor;
  1033.     return (void *)((char *)newBlockHeader + sizeof(MemoryBlockHeader));
  1034. }
  1035.  
  1036. void StandardFree(void *block, void *refcon)
  1037. {
  1038.     MemoryBlockHeader *blockHeader = (MemoryBlockHeader *)((char *)block - sizeof(MemoryBlockHeader));
  1039.     FreeRawMemory((Ptr)blockHeader);
  1040. }
  1041.  
  1042. //##############################################################################
  1043. //##############################################################################
  1044. #pragma mark -
  1045. #pragma mark FIXED SIZED ALLOCATOR (COMPACT)
  1046.  
  1047. UInt32 CountLeadingZeros(UInt32 value);
  1048.  
  1049. #if defined(powerc) || defined(_powerc)
  1050. asm UInt32 CountLeadingZeros(UInt32 value) 
  1051. {
  1052.     cntlzw    r3, r3
  1053.     blr
  1054. }
  1055. #else
  1056. UInt32 CountLeadingZeros(UInt32 value) 
  1057. {
  1058.     UInt32    whichZero = 0;
  1059.     while ((value & 0x80000000) == 0) {
  1060.         whichZero++;
  1061.         value = value << 1;
  1062.     }
  1063.     return whichZero;
  1064. }
  1065. #endif
  1066.  
  1067. void *FixedSizeCompactAlloc(size_t blockSize, void *refcon)
  1068. {
  1069.     FixedSizeCompactAllocationRoot        *sizeRoot = (FixedSizeCompactAllocationRoot *)refcon;
  1070.     FixedSizeCompactAllocationChunk        *currentChunk = sizeRoot->firstChunk;
  1071.     FreeMemoryBlockDescriptor            *whichFreeDescriptor;
  1072.     UInt32                                whichBlockIsFree,
  1073.                                         blockOffset;
  1074.     MemoryBlockHeader                    *blockHeader;
  1075.     
  1076.     //    Try to find an existing chunk with a free block.
  1077.     
  1078.     while ((currentChunk != NULL) && (currentChunk->chunkUsage == 0))
  1079.         currentChunk = currentChunk->next;
  1080.  
  1081.     //    If there is not chunk with a free block, then create
  1082.     //    a new one and put it at the beginning of the chunk list.
  1083.     
  1084.     if (currentChunk == NULL) {
  1085.  
  1086.         currentChunk = (FixedSizeCompactAllocationChunk *)AllocateRawMemory(sizeof(FixedSizeCompactAllocationChunk) + 
  1087.             (32 * (sizeRoot->blockSize + sizeof(MemoryBlockHeader) + MEMORY_BLOCK_TAILER_SIZE)));
  1088.  
  1089.         if (currentChunk == NULL) {
  1090.             return NULL;
  1091.         }
  1092.  
  1093. #if STATS_MAC_MEMORY
  1094.         gTotalFixedSizeCompactAllocated += sizeof(FixedSizeCompactAllocationChunk) + 
  1095.             (32 * (sizeRoot->blockSize + sizeof(MemoryBlockHeader) + MEMORY_BLOCK_TAILER_SIZE));
  1096.         gTotalFixedSizeCompactBlocksAllocated += 32;
  1097. #endif
  1098.  
  1099.         currentChunk->root = sizeRoot;
  1100.         currentChunk->chunkUsage = 0xFFFFFFFF;
  1101.     
  1102.         currentChunk->next = sizeRoot->firstChunk;
  1103.         sizeRoot->firstChunk = currentChunk;
  1104.         
  1105.     }
  1106.     
  1107.     //    Find the block in the chunk that is free.
  1108.     
  1109.     whichBlockIsFree = CountLeadingZeros(currentChunk->chunkUsage);
  1110.     
  1111.     //    Claim the block
  1112.     
  1113.     currentChunk->chunkUsage &= ~(0x80000000 >> whichBlockIsFree);
  1114.     
  1115.     //    Install the free descriptor
  1116.     
  1117.     whichFreeDescriptor = sizeRoot->freeDescriptorTable + whichBlockIsFree;
  1118.     
  1119.     blockOffset = (UInt32)(whichFreeDescriptor->refcon) & 0x0000FFFF;
  1120.     
  1121.     blockHeader = (MemoryBlockHeader *)((char *)currentChunk + blockOffset);
  1122.     blockHeader->blockFreeRoutine = whichFreeDescriptor;
  1123.     
  1124. #if STATS_MAC_MEMORY
  1125.     gTotalFixedSizeCompactUsed += sizeRoot->blockSize;
  1126.     gTotalFixedSizeCompactBlocksUsed++;
  1127. #endif
  1128.  
  1129.     return (void *)((char *)blockHeader + sizeof(MemoryBlockHeader));
  1130.     
  1131. }
  1132.  
  1133. void FixedSizeCompactFree(void *block, void *refcon)
  1134. {
  1135.     MemoryBlockHeader                    *blockHeader;
  1136.     UInt32                                blockNumber;
  1137.     UInt32                                blockOffset;
  1138.     FixedSizeCompactAllocationChunk        *thisChunk;
  1139.     FixedSizeCompactAllocationChunk        *currentChunk,
  1140.                                         **previousChunk = NULL;
  1141.     FixedSizeCompactAllocationRoot        *root;
  1142.     
  1143.     blockNumber = (UInt32)refcon >> 16;
  1144.     blockOffset = (UInt32)refcon & 0xFFFF;
  1145.     
  1146.     //    Find the block header and the 
  1147.     
  1148.     blockHeader = (MemoryBlockHeader *)((char *)block - sizeof(MemoryBlockHeader));
  1149.     thisChunk = (FixedSizeCompactAllocationChunk *)((char *)blockHeader - blockOffset);
  1150.  
  1151.     //    Mark the block as unused.
  1152.      
  1153.     thisChunk->chunkUsage |= (0x80000000 >> blockNumber);
  1154.  
  1155.     //    If the block is completely unused, then reclaim it
  1156.  
  1157.     root = thisChunk->root;
  1158.     currentChunk = root->firstChunk;
  1159.  
  1160.     if ((thisChunk->chunkUsage == 0xFFFFFFFF) && (currentChunk != thisChunk)) {
  1161.         
  1162.         while (currentChunk != thisChunk) {
  1163.             previousChunk = ¤tChunk->next;
  1164.             currentChunk = currentChunk->next;
  1165.         }
  1166.         
  1167.         *previousChunk = currentChunk->next;
  1168.         
  1169.         FreeRawMemory((Ptr)thisChunk);
  1170.             
  1171.     }
  1172.  
  1173. #if STATS_MAC_MEMORY
  1174.     gTotalFixedSizeCompactUsed -= root->blockSize;
  1175.     gTotalFixedSizeCompactBlocksUsed--;
  1176. #endif
  1177.         
  1178. }
  1179.  
  1180. //##############################################################################
  1181. //##############################################################################
  1182. #pragma mark -
  1183. #pragma mark FIXED SIZED ALLOCATOR (FAST)
  1184.  
  1185. void *FixedSizeFastAlloc(size_t blockSize, void *refcon)
  1186. {
  1187.     FixedSizeFastAllocationRoot        *sizeRoot = (FixedSizeFastAllocationRoot *)refcon;
  1188.     FixedSizeFastAllocationChunk    *currentChunk;
  1189.     FixedSizeFastMemoryBlockHeader    *ourBlock;
  1190.     
  1191.     //    If the free list is empty, then we have to allocate another chunk.
  1192.  
  1193.     if (sizeRoot->firstFree == NULL) {
  1194.     
  1195.         FixedSizeFastMemoryBlockHeader    *currentBlock;
  1196.         UInt32                            currentBlockNum;
  1197.  
  1198. #if STATS_MAC_MEMORY
  1199.         gTotalFixedSizeFastAllocated += sizeof(FixedSizeFastAllocationChunk) + 
  1200.             (sizeRoot->blocksPerChunk * (sizeRoot->blockSize + sizeof(FixedSizeFastMemoryBlockHeader) + MEMORY_BLOCK_TAILER_SIZE));
  1201.         gTotalFixedSizeFastBlocksAllocated += sizeRoot->blocksPerChunk;
  1202. #endif
  1203.  
  1204.         currentChunk = (FixedSizeFastAllocationChunk *)AllocateRawMemory(sizeof(FixedSizeFastAllocationChunk) + 
  1205.             (sizeRoot->blocksPerChunk * (sizeRoot->blockSize + sizeof(FixedSizeFastMemoryBlockHeader) + MEMORY_BLOCK_TAILER_SIZE)));
  1206.         if (currentChunk == NULL) {
  1207.             return NULL;
  1208.         }
  1209.     
  1210.         currentChunk->next = sizeRoot->firstChunk;
  1211.         sizeRoot->firstChunk = currentChunk;
  1212.     
  1213.         //    Thread all of the chunks blocks onto the free list.
  1214.     
  1215.         currentBlock = (FixedSizeFastMemoryBlockHeader *)((char *)currentChunk + sizeof(FixedSizeFastAllocationChunk));
  1216.     
  1217.         for (currentBlockNum = 0; currentBlockNum < sizeRoot->blocksPerChunk; currentBlockNum++) {
  1218.         
  1219.             currentBlock->nextFree = sizeRoot->firstFree;
  1220.             currentBlock->realHeader.blockFreeRoutine = sizeRoot->freeDescriptor;
  1221.             
  1222.             sizeRoot->firstFree = currentBlock;
  1223.             
  1224.             currentBlock = (FixedSizeFastMemoryBlockHeader *)((char *)currentBlock + 
  1225.                 sizeof(FixedSizeFastMemoryBlockHeader) + MEMORY_BLOCK_TAILER_SIZE + sizeRoot->blockSize);
  1226.             
  1227.         }
  1228.     
  1229.     }
  1230.  
  1231.     //    Take the first block off of the free list.  It is the one
  1232.     //    we will use.
  1233.     
  1234.     ourBlock = sizeRoot->firstFree;
  1235.     sizeRoot->firstFree = ourBlock->nextFree;
  1236.     
  1237. #if STATS_MAC_MEMORY
  1238.     gTotalFixedSizeFastBlocksUsed++;
  1239.     gTotalFixedSizeFastUsed += sizeRoot->blockSize;
  1240. #endif
  1241.     return (void *)((char *)ourBlock + sizeof(FixedSizeFastMemoryBlockHeader));
  1242.  
  1243. }
  1244.  
  1245. void FixedSizeFastFree(void *block, void *refcon)
  1246. {
  1247.     FixedSizeFastMemoryBlockHeader    *deadBlock;
  1248.     FixedSizeFastAllocationRoot        *sizeRoot = (FixedSizeFastAllocationRoot *)refcon;
  1249.     
  1250.     deadBlock = (FixedSizeFastMemoryBlockHeader *)((char *)block - sizeof(FixedSizeFastMemoryBlockHeader));
  1251.     
  1252.     //    Put the block on the free list.
  1253.     
  1254.     deadBlock->nextFree = sizeRoot->firstFree;
  1255.     sizeRoot->firstFree = deadBlock;
  1256.  
  1257. #if STATS_MAC_MEMORY
  1258.     gTotalFixedSizeFastBlocksUsed--;
  1259.     gTotalFixedSizeFastUsed -= sizeRoot->blockSize;
  1260. #endif
  1261.     
  1262. }
  1263.  
  1264. //##############################################################################
  1265. //##############################################################################
  1266. #pragma mark -
  1267. #pragma mark SMALL HEAP ALLOCATOR
  1268.  
  1269. #define SmallHeapBlockToMemoryPtr(x) ((void *)((Ptr)x + sizeof(SmallHeapBlock)))
  1270. #define MemoryPtrToSmallHeapBlock(x) ((SmallHeapBlock *)((Ptr)x - sizeof(SmallHeapBlock)))
  1271.  
  1272. #define NextSmallHeapBlock(x) ((SmallHeapBlock *)((Ptr)x + (x->blockSize & ~kBlockInUseFlag) + sizeof(SmallHeapBlock) + MEMORY_BLOCK_TAILER_SIZE))
  1273. #define PrevSmallHeapBlock(x) (x->prevBlock)
  1274.  
  1275. #define SmallHeapBlockInUse(x) ((x->blockSize & kBlockInUseFlag) != 0)
  1276. #define SmallHeapBlockNotInUse(x) ((x->blockSize & kBlockInUseFlag) == 0)
  1277.  
  1278. #define TotalSmallHeapBlockUsage(x) ((x->blockSize & ~kBlockInUseFlag) + sizeof(SmallHeapBlock) + MEMORY_BLOCK_TAILER_SIZE)
  1279.  
  1280. #define AddSmallHeapBlockToFreeList(r, x)                                                        \
  1281. {                                                                                                \
  1282.     UInt32                blockSize = x->blockSize & ~kBlockInUseFlag;                            \
  1283.     UInt32                nextBlockBin;                                                            \
  1284.     SmallHeapBlock        *tempBlock;                                                                \
  1285.     x->blockSize = blockSize        ;                                                            \
  1286.     nextBlockBin = (blockSize - kDefaultSmallHeadMinSize) >> 2;                                    \
  1287.     x->info.freeInfo.prevFree = NULL;                                                            \
  1288.     if (blockSize > kMaximumBinBlockSize) {                                                        \
  1289.         tempBlock = r->overflow;                                                                \
  1290.         x->info.freeInfo.nextFree = tempBlock;                                                    \
  1291.         if (tempBlock != NULL)                                                                    \
  1292.             tempBlock->info.freeInfo.prevFree = x;                                                \
  1293.         r->overflow = x;                                                                        \
  1294.     }                                                                                            \
  1295.     else {                                                                                        \
  1296.         tempBlock = r->bins[nextBlockBin];                                                        \
  1297.         x->info.freeInfo.nextFree = tempBlock;                                                    \
  1298.         if (tempBlock != NULL)                                                                    \
  1299.             tempBlock->info.freeInfo.prevFree = x;                                                \
  1300.         r->bins[nextBlockBin] = x;                                                                \
  1301.     }                                                                                            \
  1302. }
  1303.  
  1304. #define RemoveSmallHeapBlockFromFreeList(r, x)                                                    \
  1305. {                                                                                                \
  1306.     SmallHeapBlock        *nextFree,                                                                \
  1307.                         *prevFree;                                                                \
  1308.     UInt32                blockSize = x->blockSize;                                                \
  1309.     UInt32                nextBlockBin;                                                            \
  1310.     x->blockSize |= kBlockInUseFlag;                                                            \
  1311.     nextBlockBin = (blockSize - kDefaultSmallHeadMinSize) >> 2;                                    \
  1312.     nextFree = x->info.freeInfo.nextFree;                                                        \
  1313.     prevFree = x->info.freeInfo.prevFree;                                                        \
  1314.     if (nextFree != NULL)                                                                        \
  1315.         nextFree->info.freeInfo.prevFree = prevFree;                                            \
  1316.     if (prevFree != NULL)                                                                        \
  1317.         prevFree->info.freeInfo.nextFree = nextFree;                                            \
  1318.     else                                                                                        \
  1319.         if (blockSize > kMaximumBinBlockSize)                                                    \
  1320.             r->overflow = nextFree;                                                                \
  1321.         else                                                                                    \
  1322.             r->bins[nextBlockBin] = nextFree;                                                    \
  1323. }
  1324.  
  1325.  
  1326. #if DEBUG_MAC_MEMORY
  1327. void SmallHeapCheck(SmallHeapBlock *fromBlock)
  1328. {
  1329.     SmallHeapBlock         *previousBlock = NULL;
  1330.     
  1331.     //    Go to the first block in the list
  1332.     
  1333.     while (fromBlock->prevBlock != NULL)
  1334.         fromBlock = fromBlock->prevBlock;
  1335.     
  1336.     //    Walk the list
  1337.     
  1338.     while (fromBlock) {
  1339.     
  1340.         if (fromBlock->blockSize == 0xFFFFFFFF)
  1341.             break;
  1342.     
  1343.         if (previousBlock != NULL) {
  1344.             if (previousBlock != PrevSmallHeapBlock(fromBlock)) {
  1345.                 DebugStr("\pSmall Heap Corrupt");
  1346.                 break;
  1347.             }
  1348.         }
  1349.         previousBlock = fromBlock;
  1350.         fromBlock = NextSmallHeapBlock(fromBlock);
  1351.     
  1352.     }    
  1353.  
  1354. }
  1355. #endif
  1356.  
  1357. void *SmallHeapAlloc(size_t blockSize, void *refcon)
  1358. {
  1359.     SmallHeapRoot            *heapRoot = (SmallHeapRoot *)refcon;
  1360.     UInt32                    startingBinNum,
  1361.                             remainingBins;
  1362.     SmallHeapBlock            **currentBin;
  1363.     SmallHeapBlock            *currentBinValue;
  1364.     SmallHeapBlock            *newFreeOverflowBlock,
  1365.                             *blockToCarve,
  1366.                             *newRawBlockHeader,
  1367.                             *newRawBlockTrailer;
  1368.  
  1369.     //    Round up allocation to nearest 4 bytes.
  1370.     
  1371.     blockSize = (blockSize + 3) & 0xFFFFFFFC;
  1372.  
  1373.     //    Try to find the best fit in one of the bins.
  1374.     
  1375.     startingBinNum = (blockSize - kDefaultSmallHeadMinSize) >> 2;
  1376.     
  1377.     currentBin = heapRoot->bins + startingBinNum;
  1378.     currentBinValue = *currentBin;
  1379.         
  1380.     //    If the current bin has something in it,
  1381.     //    then use it for our allocation.
  1382.     
  1383.     if (currentBinValue != NULL) {
  1384.         
  1385.         RemoveSmallHeapBlockFromFreeList(heapRoot, currentBinValue);
  1386.  
  1387.         currentBinValue->info.inUseInfo.freeProc.blockFreeRoutine = heapRoot->blockFreeRoutine;
  1388.  
  1389. #if STATS_MAC_MEMORY
  1390.         gTotalSmallHeapBlocksUsed++;
  1391.         gTotalSmallHeapUsed += TotalSmallHeapBlockUsage(currentBinValue);
  1392. #endif
  1393.  
  1394.         return SmallHeapBlockToMemoryPtr(currentBinValue);
  1395.  
  1396.     }
  1397.  
  1398.     //    Otherwise, try to carve up an existing larger block.
  1399.  
  1400.     remainingBins = kDefaultSmallHeapBins - startingBinNum - 1;
  1401.     blockToCarve = NULL;
  1402.     
  1403.     while (remainingBins--) {
  1404.     
  1405.         currentBin++;
  1406.     
  1407.         currentBinValue = *currentBin;
  1408.         
  1409.         if (currentBinValue != NULL) {
  1410.             blockToCarve = currentBinValue;
  1411.             break;
  1412.         }
  1413.         
  1414.     }
  1415.  
  1416.     //    Try carving up up a block from the overflow bin.
  1417.     
  1418.     if (blockToCarve == NULL)
  1419.         blockToCarve = heapRoot->overflow;
  1420.     
  1421. doCarve:
  1422.     
  1423.     while (blockToCarve != NULL) {
  1424.     
  1425.         SInt32    blockToCarveSize = blockToCarve->blockSize;
  1426.     
  1427.         //    If the owerflow block is big enough to house the
  1428.         //    allocation, then use it.
  1429.     
  1430.         if (blockToCarveSize >= blockSize) {
  1431.         
  1432.             SInt32                leftovers;
  1433.         
  1434.             //    Remove the block from the free list... we will
  1435.             //    be using it for the allocation...
  1436.             
  1437.             RemoveSmallHeapBlockFromFreeList(heapRoot, blockToCarve);
  1438.  
  1439.             //    If taking our current allocation out of
  1440.             //    the overflow block would still leave enough
  1441.             //    room for another allocation out of the 
  1442.             //    block, then split the block up.
  1443.             
  1444.             leftovers = blockToCarveSize - sizeof(SmallHeapBlock) - MEMORY_BLOCK_TAILER_SIZE - blockSize;
  1445.             
  1446.             if (leftovers >= kDefaultSmallHeadMinSize) {
  1447.             
  1448.                 SmallHeapBlock        *leftoverBlock;
  1449.                 SmallHeapBlock        *nextBlock;
  1450.             
  1451.                 nextBlock = NextSmallHeapBlock(blockToCarve);
  1452.                 
  1453.                 //    Create a new block out of the leftovers
  1454.                 
  1455.                 leftoverBlock = (SmallHeapBlock *)((char *)blockToCarve + 
  1456.                     sizeof(SmallHeapBlock) + blockSize + MEMORY_BLOCK_TAILER_SIZE); 
  1457.             
  1458.                 //    Add the block to linked list of blocks in this raw
  1459.                 //    allocation chunk.
  1460.             
  1461.                 nextBlock->prevBlock = leftoverBlock;
  1462.                 blockToCarve->blockSize = blockSize | kBlockInUseFlag;        
  1463.                     
  1464.                 leftoverBlock->prevBlock = blockToCarve;
  1465.                 leftoverBlock->blockSize = leftovers;
  1466.                 
  1467.                 //    And add the block to a free list, which will either be
  1468.                 //    one of the sized bins or the overflow list, depending
  1469.                 //    on its size.
  1470.             
  1471.                 AddSmallHeapBlockToFreeList(heapRoot, leftoverBlock);
  1472.                         
  1473.             }
  1474.         
  1475.             blockToCarve->info.inUseInfo.freeProc.blockFreeRoutine = heapRoot->blockFreeRoutine;
  1476.  
  1477. #if STATS_MAC_MEMORY
  1478.             gTotalSmallHeapBlocksUsed++;
  1479.             gTotalSmallHeapUsed += TotalSmallHeapBlockUsage(blockToCarve);
  1480. #endif
  1481.             return SmallHeapBlockToMemoryPtr(blockToCarve);
  1482.                         
  1483.         } 
  1484.     
  1485.         blockToCarve = blockToCarve->info.freeInfo.nextFree;
  1486.     
  1487.     }
  1488.     
  1489.     //    No existing block was suitable.  We need to allocate
  1490.     //    some raw memory to try again.
  1491.     
  1492. #if STATS_MAC_MEMORY
  1493.     gTotalSmallHeapAllocated += kSmallHeapSize;
  1494. #endif
  1495.  
  1496.     newRawBlockHeader = (SmallHeapBlock *)AllocateRawMemory(kSmallHeapSize);
  1497.     if (newRawBlockHeader == NULL) {
  1498.         //    If all else fails, try allocating out of the NewPtr heap.
  1499.         return StandardAlloc(blockSize, 0);
  1500.     }
  1501.  
  1502.     //    The first few bytes of the block are a dummy header
  1503.     //    which is a block of size zero that is always alloacted.  
  1504.     //    This allows our coalesce code to work without modification
  1505.     //    on the edge case of coalescing the first real block.
  1506.  
  1507.     newRawBlockHeader->prevBlock = NULL;
  1508.     newRawBlockHeader->blockSize = kBlockInUseFlag;
  1509.     newRawBlockHeader->info.inUseInfo.freeProc.blockFreeRoutine = NULL;
  1510.     
  1511.     newFreeOverflowBlock = NextSmallHeapBlock(newRawBlockHeader);
  1512.     
  1513.     newFreeOverflowBlock->prevBlock = newRawBlockHeader;
  1514.     newFreeOverflowBlock->blockSize = kSmallHeapSize - 3 * sizeof(SmallHeapBlock) - 3 * MEMORY_BLOCK_TAILER_SIZE;
  1515.  
  1516.     //    The same is true for the last few bytes in the block 
  1517.     //    as well.
  1518.     
  1519.     newRawBlockTrailer = (SmallHeapBlock *)(((Ptr)newRawBlockHeader) + kSmallHeapSize - sizeof(SmallHeapBlock) - MEMORY_BLOCK_TAILER_SIZE);
  1520.     newRawBlockTrailer->prevBlock = newFreeOverflowBlock;
  1521.     newRawBlockTrailer->blockSize = kBlockInUseFlag | 0xFFFFFFFF;
  1522.     newRawBlockTrailer->info.inUseInfo.freeProc.blockFreeRoutine = NULL;
  1523.     
  1524.     AddSmallHeapBlockToFreeList(heapRoot, newFreeOverflowBlock);
  1525.     
  1526.     blockToCarve = newFreeOverflowBlock;
  1527.     
  1528.     //    Try again.
  1529.     
  1530.     goto doCarve;
  1531.  
  1532. }
  1533.  
  1534. void SmallHeapFree(void *address, void *refcon)
  1535. {
  1536.     SmallHeapRoot            *heapRoot = (SmallHeapRoot *)refcon;
  1537.     SmallHeapBlock            *deadBlock,
  1538.                             *prevBlock,
  1539.                             *nextBlock;
  1540.                 
  1541.     deadBlock = MemoryPtrToSmallHeapBlock(address);
  1542.  
  1543. #if STATS_MAC_MEMORY
  1544.     gTotalSmallHeapBlocksUsed--;
  1545.     gTotalSmallHeapUsed -= TotalSmallHeapBlockUsage(deadBlock);
  1546. #endif
  1547.  
  1548.     //    If the block after us is free, then coalesce with it.
  1549.     
  1550.     nextBlock = NextSmallHeapBlock(deadBlock);
  1551.     prevBlock = PrevSmallHeapBlock(deadBlock);
  1552.     
  1553.     if (SmallHeapBlockNotInUse(nextBlock)) {    
  1554.         RemoveSmallHeapBlockFromFreeList(heapRoot, nextBlock);
  1555.         deadBlock->blockSize += TotalSmallHeapBlockUsage(nextBlock);
  1556.         nextBlock = NextSmallHeapBlock(nextBlock);
  1557.     }
  1558.     
  1559.     //    If the block before us is free, then coalesce with it.
  1560.     
  1561.     if (SmallHeapBlockNotInUse(prevBlock)) {
  1562.         RemoveSmallHeapBlockFromFreeList(heapRoot, prevBlock);
  1563.         prevBlock->blockSize = ((Ptr)nextBlock - (Ptr)prevBlock) - sizeof(SmallHeapBlock) - MEMORY_BLOCK_TAILER_SIZE;
  1564.         AddSmallHeapBlockToFreeList(heapRoot, prevBlock);
  1565.         deadBlock = prevBlock;
  1566.     }
  1567.     
  1568.     else {    
  1569.         AddSmallHeapBlockToFreeList(heapRoot, deadBlock);
  1570.     }
  1571.     
  1572.     nextBlock->prevBlock = deadBlock;
  1573.  
  1574. }
  1575.  
  1576. //##############################################################################
  1577. //##############################################################################
  1578. #pragma mark -
  1579. #pragma mark TRACKING MEMORY MANAGER MEMORY
  1580.  
  1581. #if DEBUG_MAC_MEMORY
  1582. #if GENERATINGPOWERPC
  1583.  
  1584. enum {
  1585.     kFigmentBlockHashTableSize            = 128,
  1586.     kFigmentBlockTotalTrackedBlocks        = 8192
  1587. };
  1588.  
  1589. typedef struct FigmentBlockInformation FigmentBlockInformation;
  1590.  
  1591. struct FigmentBlockInformation {
  1592.     FigmentBlockInformation            *next;
  1593.     void                            *allocation;
  1594.     AllocationSite                    *allocator;
  1595. };
  1596.  
  1597. enum {
  1598.     uppNewHandleProcInfo = kRegisterBased
  1599.          | RESULT_SIZE(SIZE_CODE(sizeof(Handle)))
  1600.          | REGISTER_RESULT_LOCATION(kRegisterA0)
  1601.          | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(UInt16)))
  1602.          | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(Size))),
  1603.     uppNewPtrProcInfo = kRegisterBased
  1604.          | RESULT_SIZE(SIZE_CODE(sizeof(Handle)))
  1605.          | REGISTER_RESULT_LOCATION(kRegisterA0)
  1606.          | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(UInt16)))
  1607.          | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(Size))),
  1608.     uppDisposeHandleProcInfo = kRegisterBased
  1609.          | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(UInt16)))
  1610.          | REGISTER_ROUTINE_PARAMETER(2, kRegisterA0, SIZE_CODE(sizeof(Handle))),
  1611.     uppDisposePtrProcInfo = kRegisterBased
  1612.          | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(UInt16)))
  1613.          | REGISTER_ROUTINE_PARAMETER(2, kRegisterA0, SIZE_CODE(sizeof(Ptr)))
  1614. };
  1615.  
  1616. extern pascal Handle NewHandlePatch(UInt16 trapWord, Size byteCount);
  1617. extern pascal Ptr NewPtrPatch(UInt16 trapWord, Size byteCount);
  1618. extern pascal void DisposeHandlePatch(UInt16 trapWord, Handle deadHandle);
  1619. extern pascal void DisposePtrPatch(UInt16 trapWord, Ptr deadPtr);
  1620.  
  1621. RoutineDescriptor    gNewHandlePatchRD = BUILD_ROUTINE_DESCRIPTOR(uppNewHandleProcInfo, &NewHandlePatch);
  1622. RoutineDescriptor    gNewPtrPatchRD = BUILD_ROUTINE_DESCRIPTOR(uppNewPtrProcInfo, &NewPtrPatch);
  1623. RoutineDescriptor    gDisposeHandlePatchRD = BUILD_ROUTINE_DESCRIPTOR(uppDisposeHandleProcInfo, &DisposeHandlePatch);
  1624. RoutineDescriptor    gDisposePtrPatchRD = BUILD_ROUTINE_DESCRIPTOR(uppDisposePtrProcInfo, &DisposePtrPatch);
  1625.  
  1626. UniversalProcPtr    gNewHandlePatchCallThru = NULL;
  1627. UniversalProcPtr     gNewPtrPatchCallThru = NULL;
  1628. UniversalProcPtr    gDisposeHandlePatchCallThru = NULL;
  1629. UniversalProcPtr     gDisposePtrPatchCallThru = NULL;
  1630.  
  1631. Ptr                            figmentAllocationList = NULL;
  1632. FigmentBlockInformation        *figmentAllocationListHash[kFigmentBlockHashTableSize];
  1633. FigmentBlockInformation        *figmentAllocationFreeList = NULL;
  1634.  
  1635. void AddBlockToActiveList(void *newBlock, AllocationSite *alocationSite) 
  1636. {
  1637.  
  1638.     //    If we don't already have a block to store the list
  1639.     //    of our active figment blocks, then create one.
  1640.  
  1641.     if (figmentAllocationList == NULL) {
  1642.  
  1643.         UInt32    currentBlock;
  1644.  
  1645.         figmentAllocationList = (Ptr)CallOSTrapUniversalProc(gNewPtrPatchCallThru, uppNewPtrProcInfo, 0x031E, kFigmentBlockTotalTrackedBlocks * sizeof(FigmentBlockInformation));
  1646.  
  1647.         //    Thread all of the new blocks onto the free list.
  1648.  
  1649.         for (currentBlock = 0; currentBlock < kFigmentBlockTotalTrackedBlocks; currentBlock++) {
  1650.  
  1651.             FigmentBlockInformation    *currentBlockPtr;
  1652.  
  1653.             currentBlockPtr = (FigmentBlockInformation * )figmentAllocationList + currentBlock;
  1654.             currentBlockPtr->next = figmentAllocationFreeList;
  1655.             figmentAllocationFreeList = currentBlockPtr;
  1656.  
  1657.         }
  1658.  
  1659.     }
  1660.     
  1661.     //    If we have a free block on the free list, use it
  1662.     //    to store the information about this allocation.
  1663.     
  1664.     if (figmentAllocationFreeList != NULL) {
  1665.     
  1666.         UInt32                        hashKey = ((UInt32)newBlock >> 2) % kFigmentBlockHashTableSize;
  1667.         FigmentBlockInformation        *blockToUse;
  1668.     
  1669.         //    Remove the block from the free list.
  1670.     
  1671.         blockToUse = figmentAllocationFreeList;
  1672.         figmentAllocationFreeList = blockToUse->next;
  1673.  
  1674.         //    Add it to the hash table of active blocks in the appropriate place.
  1675.         
  1676.         blockToUse->next = figmentAllocationListHash[hashKey];
  1677.         figmentAllocationListHash[hashKey] = blockToUse;
  1678.         
  1679.         //    And fill in its relevant information.
  1680.         
  1681.         blockToUse->allocation = newBlock;
  1682.         blockToUse->allocator = alocationSite;
  1683.     
  1684.     }
  1685.     
  1686. }
  1687.  
  1688. void RemoveBlockFromActiveList(void *deadBlock) 
  1689. {
  1690.     UInt32                        hashKey = ((UInt32)deadBlock >> 2) % kFigmentBlockHashTableSize;
  1691.     FigmentBlockInformation        *blockToUse;
  1692.     FigmentBlockInformation        **previousBlockToUse = NULL;
  1693.     
  1694.     blockToUse = figmentAllocationListHash[hashKey];
  1695.     previousBlockToUse = figmentAllocationListHash + hashKey;
  1696.     
  1697.     while (blockToUse) {
  1698.     
  1699.         if (blockToUse->allocation == deadBlock) {
  1700.             if (blockToUse->allocator != NULL)
  1701.                 blockToUse->allocator->frees++;
  1702.             *previousBlockToUse = blockToUse->next;
  1703.             blockToUse->next = figmentAllocationFreeList;
  1704.             figmentAllocationFreeList = blockToUse;
  1705.             break;
  1706.         }
  1707.     
  1708.         previousBlockToUse = &(blockToUse->next);
  1709.         blockToUse = blockToUse->next;
  1710.     
  1711.     }
  1712.     
  1713. }
  1714.  
  1715. void GetCurrentNativeStackTrace(void **stackCrawl)
  1716. {
  1717.     void    *currentSP;
  1718.     void    *interfaceLibSP;
  1719.     void    *callerFirstStackFrame;
  1720.     void    *callerSP;
  1721.     UInt32    stackFrameLevel;
  1722.     UInt8    isPowerPC = true;
  1723.     
  1724.     memset(stackCrawl, 0, sizeof(void *) * kRecordingDepthOfStackLevels);
  1725.  
  1726. #if !GENERATINGPOWERPC
  1727.     return;
  1728. #endif
  1729.  
  1730.     //    If the current SP is not in our heap, then bail (OT is evil).
  1731.     
  1732. #if GENERATINGPOWERPC
  1733.     currentSP = GetCurrentStackPointer();
  1734. #endif
  1735.  
  1736.     if ((currentSP > gOurApplicationHeapMax) || (currentSP < gOurApplicationHeapBase))
  1737.         return;
  1738.         
  1739.     interfaceLibSP = *((void **)currentSP);
  1740.     
  1741.     callerFirstStackFrame = interfaceLibSP;
  1742.     
  1743.     //    Walk up the stack until we get the first frame
  1744.     //    which is actually in our executable's heap... note that
  1745.     //    this only works if VM is OFF!
  1746.     
  1747.     while (1) {
  1748.  
  1749.         void    *nextFrame;
  1750.  
  1751.         if ((nextFrame > gOurApplicationHeapMax) || (nextFrame < gOurApplicationHeapBase))
  1752.             return;
  1753.         
  1754.         //    Walk the stack differently whether we are at a
  1755.         //    PowerPC or 68K frame...
  1756.  
  1757.         if (isPowerPC) {
  1758.  
  1759.             void    *framePC;
  1760.  
  1761.             //    If we are PowerPC, check to see if the PC
  1762.             //    corresponding to the current frame is in the
  1763.             //    the app's code space.  If so, then we are
  1764.             //    done and we break out.
  1765.             
  1766.             framePC = *((void **)callerFirstStackFrame + 2);
  1767.             if ((framePC < gOurApplicationHeapMax) && (framePC > gOurApplicationHeapBase))
  1768.                 break;
  1769.                 
  1770.             //    Otherwise, check the pointer to the next
  1771.             //    stack frame.  If its low bit is set, then
  1772.             //    it is a mixed-mode switch frame, and 
  1773.             //    we need to switch to 68K frames.
  1774.  
  1775.             nextFrame = *((void **)callerFirstStackFrame);
  1776.             if (((UInt32)nextFrame & 0x00000001) != 0) {
  1777.                 callerFirstStackFrame = (void *)((UInt32)nextFrame & 0xFFFFFFFE);
  1778.                 isPowerPC = false;
  1779.             } else
  1780.                 callerFirstStackFrame = nextFrame;
  1781.  
  1782.         }
  1783.     
  1784.         else {
  1785.             
  1786.             //    68K case:  If the location immediately above the stack
  1787.             //    frame pointer is -1, then we are at a switch frame,
  1788.             //    move back to PowerPC.
  1789.  
  1790.             if (*((UInt32 *)callerFirstStackFrame - 1) == 0xFFFFFFFF)
  1791.                 isPowerPC = true;
  1792.             callerFirstStackFrame = *((void **)callerFirstStackFrame);
  1793.  
  1794.         }
  1795.     
  1796.     }
  1797.     
  1798.     callerSP = callerFirstStackFrame;
  1799.     
  1800.     for (stackFrameLevel = 0; stackFrameLevel < kRecordingDepthOfStackLevels; stackFrameLevel++) {
  1801.     
  1802.         if ((callerSP > gOurApplicationHeapMax) || (callerSP < gOurApplicationHeapBase))
  1803.             return;
  1804.             
  1805.         stackCrawl[stackFrameLevel] = *(((void **)callerSP) + 2);
  1806.         
  1807.         callerSP = *((void **)callerSP);
  1808.     
  1809.     }
  1810.  
  1811. }
  1812.  
  1813. extern pascal Handle NewHandlePatch(UInt16 trapWord, Size byteCount)
  1814. {
  1815.     void            *stackCrawl[kRecordingDepthOfStackLevels];
  1816.     Handle            resultHandle;
  1817.     AllocationSite    *allocationSite;
  1818.     
  1819.     if (gTrackLeaks)
  1820.         GetCurrentNativeStackTrace(stackCrawl);
  1821.  
  1822.     resultHandle = (Handle)CallOSTrapUniversalProc(gNewHandlePatchCallThru, uppNewHandleProcInfo, trapWord, byteCount);
  1823.  
  1824.     if (gTrackLeaks && resultHandle) {
  1825.         allocationSite = AddAllocationSite(kAllocationSiteNewHandle, stackCrawl);
  1826.         AddBlockToActiveList((void *)resultHandle, allocationSite);
  1827.         gOutstandingHandles++;
  1828.     }
  1829.     
  1830.     return resultHandle;
  1831.     
  1832. }
  1833.  
  1834. extern pascal Ptr NewPtrPatch(UInt16 trapWord, Size byteCount)
  1835. {    
  1836.     void            *stackCrawl[kRecordingDepthOfStackLevels];
  1837.     Ptr                resultPtr;
  1838.     AllocationSite    *allocationSite;
  1839.  
  1840.     if (gTrackLeaks)
  1841.         GetCurrentNativeStackTrace(stackCrawl);
  1842.     
  1843.     resultPtr = (Ptr)CallOSTrapUniversalProc(gNewPtrPatchCallThru, uppNewPtrProcInfo, trapWord, byteCount);
  1844.  
  1845.     if (gTrackLeaks && resultPtr) {
  1846.         allocationSite = AddAllocationSite(kAllocationSiteNewPtr, stackCrawl);
  1847.         AddBlockToActiveList((void *)resultPtr, allocationSite);
  1848.         gOutstandingPointers++;
  1849.     }
  1850.     
  1851.     return resultPtr;
  1852.     
  1853. }
  1854.  
  1855. pascal void DisposeHandlePatch(UInt16 trapWord, Handle deadHandle)
  1856. {
  1857.     if (gTrackLeaks) {
  1858.         RemoveBlockFromActiveList(deadHandle);
  1859.         gOutstandingHandles--;
  1860.     }
  1861.     CallOSTrapUniversalProc(gDisposeHandlePatchCallThru, uppDisposeHandleProcInfo, trapWord, deadHandle);
  1862. }
  1863.  
  1864. pascal void DisposePtrPatch(UInt16 trapWord, Ptr deadPtr)
  1865. {
  1866.     if (gTrackLeaks) {
  1867.         RemoveBlockFromActiveList(deadPtr);
  1868.         gOutstandingPointers--;
  1869.     }
  1870.     CallOSTrapUniversalProc(gDisposePtrPatchCallThru, uppDisposePtrProcInfo, trapWord, deadPtr);
  1871. }
  1872.  
  1873.  
  1874. void InstallMemoryManagerPatches(void)
  1875. {
  1876.     ProcessSerialNumber    thisProcess = { 0, kCurrentProcess };
  1877.     ProcessInfoRec        processInfo;
  1878.  
  1879.     processInfo.processInfoLength = sizeof(processInfo);
  1880.     processInfo.processName = NULL;
  1881.     processInfo.processAppSpec = NULL;
  1882.  
  1883.     GetProcessInformation(&thisProcess, &processInfo);
  1884.  
  1885.     gOurApplicationHeapBase = processInfo.processLocation;
  1886.     gOurApplicationHeapMax = (Ptr)gOurApplicationHeapBase + processInfo.processSize;
  1887.  
  1888.     gNewHandlePatchCallThru = GetOSTrapAddress(0x0122);
  1889.     SetOSTrapAddress(&gNewHandlePatchRD, 0x0122);
  1890.     
  1891.     gNewPtrPatchCallThru = GetOSTrapAddress(0x011E);
  1892.     SetOSTrapAddress(&gNewPtrPatchRD, 0x011E);
  1893.  
  1894.     gDisposeHandlePatchCallThru = GetOSTrapAddress(0x023);
  1895.     SetOSTrapAddress(&gDisposeHandlePatchRD, 0x023);
  1896.  
  1897.     gDisposePtrPatchCallThru = GetOSTrapAddress(0x001F);
  1898.     SetOSTrapAddress(&gDisposePtrPatchRD, 0x001F);
  1899.  
  1900. }
  1901.  
  1902. #else
  1903.  
  1904. void InstallMemoryManagerPatches(void)
  1905. {
  1906.     
  1907. }
  1908.  
  1909. #endif
  1910. #endif
  1911.  
  1912.  
  1913.  
  1914.