home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / mac / MacMemoryAllocator / src / StdCLevel.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  69.8 KB  |  2,290 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 <OSUtils.h>
  21. #include <Gestalt.h>
  22. #include <Processes.h>
  23.  
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <stdio.h>
  27.  
  28. #ifndef NSPR20
  29. #include "prmacos.h"
  30. #include "prthread.h"
  31. #endif
  32.  
  33. #include "TypesAndSwitches.h"
  34. #include "MacMemAllocator.h"
  35.  
  36. #if STATS_MAC_MEMORY
  37. #ifdef XP_MAC
  38. #include <Types.h>
  39. #include <unistd.h>
  40. #include <fcntl.h>
  41. #endif /* XP_MAC */
  42.  
  43. #include "prglobal.h"
  44. #include "prfile.h"
  45.  
  46. static void WriteString ( PRFileHandle file, char * string );
  47. #endif
  48.  
  49. #include "MemoryTracker.h"
  50.  
  51. #define    DEBUG_ALLOCATION_CHUNKS    0
  52. #define    DEBUG_MAC_ALLOCATORS    0
  53. #define    DEBUG_DONT_TRACK_MALLOC    0
  54. #define    DEBUG_TRACK_MACOS_MEMS    1
  55.  
  56. //##############################################################################
  57. //##############################################################################
  58. #pragma mark malloc DECLARATIONS
  59.  
  60. static Boolean    gInsideCacheFlush = false;
  61.  
  62. //##############################################################################
  63. //##############################################################################
  64. #pragma mark -
  65. #pragma mark malloc DEBUG DECLARATIONS
  66.  
  67. #if STATS_MAC_MEMORY
  68. UInt32 gSmallAllocationTotalCountTable[1025];
  69. UInt32 gSmallAllocationActiveCountTable[1025];
  70. UInt32 gSmallAllocationMaxCountTable[1025];
  71. #endif
  72.  
  73. #if DEBUG_HEAP_INTEGRITY
  74.  
  75. enum {
  76.     kFreeBlockHeaderTag        = 'FREE',
  77.     kFreeBlockTrailerTag    = 'free',
  78.     kUsedBlockHeaderTag        = 'USED',
  79.     kUsedBlockTrailerTag    = 'used',
  80.     kRefdBlockHeaderTag        = 'REFD',
  81.     kRefdBlockTrailerTag    = 'refd',
  82.     kFreeMemoryFillPattern     = 0xEF,
  83.     kUsedMemoryFillPattern    = 0xDB
  84. };
  85.  
  86. MemoryBlockHeader *    gFirstAllocatedBlock = NULL;
  87. MemoryBlockHeader *    gLastAllocatedBlock = NULL;
  88.  
  89. #endif
  90.  
  91. extern void    *        gOurApplicationHeapBase;
  92. extern void    *        gOurApplicationHeapMax;
  93.  
  94. #if DEBUG_MAC_MEMORY || DEBUG_HEAP_INTEGRITY
  95.  
  96. UInt32                gOutstandingPointers = 0;
  97. UInt32                gOutstandingHandles = 0;
  98.  
  99. #if DEBUG_MAC_MEMORY
  100.  
  101. #define    kMaxInstructionScanDistance    4096
  102.  
  103. AllocationSet *        gFixedSizeAllocatorSet = NULL;
  104. AllocationSet *        gSmallHeapAllocatorSet = NULL;
  105. AllocationSet *        gLargeBlockAllocatorSet = NULL;
  106.  
  107. void        *        gMemoryTop;
  108.  
  109. static void PrintStackCrawl ( void ** stackCrawl, char * name );
  110. static void CatenateRoutineNameFromPC( char * string, void *currentPC );
  111. static void PrintHexNumber( char * string, UInt32 hexNumber );
  112. pascal void TrackerExitToShellPatch(void);
  113.  
  114. /* patch on exit to shell to always print out our log */
  115. UniversalProcPtr    gExitToShellPatchCallThru = NULL;
  116. #if GENERATINGCFM
  117. enum {
  118.     uppExitToShellProcInfo                 = kPascalStackBased
  119. };
  120.  
  121. RoutineDescriptor     gExitToShellPatchRD = BUILD_ROUTINE_DESCRIPTOR(uppExitToShellProcInfo, &TrackerExitToShellPatch);
  122. #else
  123. #define gExitToShellPatchRD ExitToShellPatch
  124. #endif
  125.  
  126. #endif
  127.  
  128. #endif
  129.  
  130. #if STATS_MAC_MEMORY
  131. void DumpCurrentMemoryStatistics(char *operation);
  132. void PrintEfficiency(PRFileHandle file, UInt32 current, UInt32 total);
  133.  
  134.  
  135. #endif
  136.  
  137. asm void AsmFree(void *);
  138. asm void *AsmMalloc(size_t);
  139.  
  140. //##############################################################################
  141. //##############################################################################
  142. #pragma mark -
  143. #pragma mark malloc DEBUG CONTROL VARIABLES
  144.  
  145. #if DEBUG_HEAP_INTEGRITY
  146.  
  147. UInt32                        gVerifyHeapOnEveryMalloc            = 0;
  148. UInt32                        gVerifyHeapOnEveryFree                = 0;
  149. UInt32                        gFillUsedBlocksWithPattern            = 0;
  150. UInt32                        gFillFreeBlocksWithPattern            = 1;
  151. UInt32                        gOnMallocFailureReturnDEADBEEF        = 0;
  152. SInt32                        gFailToAllocateAfterNMallocs        = -1;
  153.  
  154. SInt32                        gTagReferencedBlocks                = 0;            // for best effect, turn on gFillFreeBlocksWithPattern also
  155.  
  156. #endif
  157.  
  158. #if DEBUG_MAC_MEMORY || DEBUG_HEAP_INTEGRITY
  159. UInt32                        gDontActuallyFreeMemory                = 0;
  160. UInt32                        gNextBlockNum = 0;
  161. #endif
  162.  
  163. //##############################################################################
  164. //##############################################################################
  165.  
  166. #if STATS_MAC_MEMORY
  167.  
  168. UInt32        gTotalFixedSizeBlocksAllocated = 0;
  169. UInt32        gTotalFixedSizeBlocksUsed = 0;
  170. UInt32        gTotalFixedSizeAllocated = 0;
  171. UInt32        gTotalFixedSizeUsed = 0;
  172.  
  173. UInt32        gTotalSmallHeapBlocksAllocated = 0;
  174. UInt32        gTotalSmallHeapBlocksUsed = 0;
  175. UInt32        gTotalSmallHeapAllocated = 0;
  176. UInt32        gTotalSmallHeapUsed = 0;
  177.  
  178. #endif
  179.  
  180.  
  181. //##############################################################################
  182. //##############################################################################
  183. #pragma mark -
  184. #pragma mark malloc AND free
  185.  
  186. /*
  187.  * These are kinda ugly as all the DEBUG code is ifdefed inside here, but I really
  188.  * don't like the idea of having multiple implementations of the basic malloc
  189.  */
  190.  
  191. void *malloc(size_t blockSize)
  192. {
  193.     void                    *        newBlock;
  194.     AllocMemoryBlockDescriptor *    whichAllocator;
  195. #if DEBUG_HEAP_INTEGRITY
  196.     MemoryBlockHeader *                newBlockHeader;
  197.     MemoryBlockTrailer *            newBlockTrailer;    
  198. #endif
  199. #if DEBUG_HEAP_INTEGRITY || DEBUG_MAC_MEMORY
  200.     size_t                            newCompositeSize = blockSize + sizeof(MemoryBlockHeader) + MEMORY_BLOCK_TAILER_SIZE;
  201.     size_t                            blockSizeCopy = blockSize;
  202. #endif
  203. #if DEBUG_MAC_MEMORY
  204.     void *                            stackCrawl[ kStackDepth ];
  205. #endif
  206.  
  207.     /*
  208.      * I hate sticking this here, but static initializers may allocate memory and so
  209.      * we cannot initialize memory through our normal execution path. We could put it in
  210.      * more efficient places inside the allocators, but then it needs to be added to all
  211.      * the allocators and that seems rather bug-prone...
  212.      */
  213.     if ( gMemoryInitialized == false )
  214.         {
  215.         MacintoshInitializeMemory();
  216.         }
  217.     
  218. #if DEBUG_HEAP_INTEGRITY
  219.     if (gVerifyHeapOnEveryMalloc)
  220.         VerifyMallocHeapIntegrity();
  221.         
  222.     if (gFailToAllocateAfterNMallocs != -1) {
  223.         if (gFailToAllocateAfterNMallocs-- == 0)
  224.             return NULL;
  225.     }
  226. #endif
  227.  
  228. #if STATS_MAC_MEMORY
  229.  
  230.     if (blockSizeCopy >= 1024)
  231.         blockSizeCopy = 1024;
  232.  
  233.     gSmallAllocationTotalCountTable[blockSizeCopy]++;
  234.     gSmallAllocationActiveCountTable[blockSizeCopy]++;
  235.     if (gSmallAllocationActiveCountTable[blockSizeCopy] > gSmallAllocationMaxCountTable[blockSizeCopy])
  236.         gSmallAllocationMaxCountTable[blockSizeCopy] = gSmallAllocationActiveCountTable[blockSizeCopy];
  237.  
  238. #endif
  239.  
  240.     /* THE REAL MALLOC CODE */
  241.     
  242.     /* which allocator should we use? */
  243.     if (blockSize <= kMaxTableAllocatedBlockSize)
  244.         {
  245.         whichAllocator = gFastMemSmallSizeAllocators + ((blockSize + 3) >> 2);
  246.         }
  247.     else
  248.         {
  249.         /* large blocks come out of entry 0 */
  250.         whichAllocator = &gFastMemSmallSizeAllocators[ 0 ];
  251.         }
  252.     
  253.     newBlock = (whichAllocator->blockAllocRoutine)(blockSize, whichAllocator->root);
  254.  
  255.     if ( newBlock == NULL )
  256.         {
  257.         /* we need to ensure no one else tries to flush cache's while we do */
  258.         /* This may mean that we allocate temp mem while flushing the cache that we would */
  259.         /* have had space for after the flush, but life sucks... */
  260.         
  261.         if ( gInsideCacheFlush == false )
  262.             {            
  263.             /* we didn't get it. Flush some caches and try again */
  264.             gInsideCacheFlush = true;
  265.             CallCacheFlushers ( blockSize );
  266.             gInsideCacheFlush = false;
  267.             
  268.             newBlock = (char *)(whichAllocator->blockAllocRoutine)(blockSize, whichAllocator->root);
  269.             }
  270.  
  271.         /* if we still don't have it, try allocating a new chunk */
  272.         if ( newBlock == NULL )
  273.             {
  274.             if ( (whichAllocator->chunkAllocRoutine)( blockSize, whichAllocator->root ) != NULL )
  275.                 {
  276.                 newBlock = (char *)(whichAllocator->blockAllocRoutine)(blockSize, whichAllocator->root);
  277.                 }
  278.             
  279.             /*
  280.              * If that fails, we may be able to succeed by choosing the next biggest block size.
  281.              * We should signal the user that things are sucking though. We will never be able
  282.              * to allocate a large block at this point. We might be able to get a small block.
  283.              */
  284.             if ( newBlock == NULL )
  285.                 {
  286.                 if ( blockSize <= kMaxTableAllocatedBlockSize )
  287.                     {
  288.                     UInt32    allocatorIndex;
  289.                     
  290.                     allocatorIndex = ((blockSize + 3) >> 2);
  291.                     
  292.                     /* of course, this will only work for small blocks */
  293.                     while ( ++allocatorIndex <= (( kMaxTableAllocatedBlockSize >> 2 ) + 1 ))
  294.                         {
  295.                         if ( allocatorIndex <= ( kMaxTableAllocatedBlockSize >> 2 ) )
  296.                             {
  297.                             /* try another small block allocator */
  298.                             whichAllocator = &gFastMemSmallSizeAllocators[ allocatorIndex ];
  299.                             }
  300.                         else
  301.                             {
  302.                             /* try the large block allocator */
  303.                             whichAllocator = &gFastMemSmallSizeAllocators[ 0 ];
  304.                             }
  305.                             
  306.                         newBlock = (char *)(whichAllocator->blockAllocRoutine)(blockSize, whichAllocator->root);
  307.                         if ( newBlock != NULL )
  308.                             {
  309.                             break;
  310.                             }
  311.                         }
  312.                     }
  313.                 
  314.                 /* tell the FE */
  315.                 CallFE_LowMemory();
  316.                 }
  317.             
  318.             /* now, if we don't have any memory, then we really suck */
  319.             if ( newBlock == NULL )
  320.                 {
  321.         #if DEBUG_HEAP_INTEGRITY
  322.                 if (gOnMallocFailureReturnDEADBEEF)
  323.                     {
  324.                     return (void *)0xDEADBEEF;
  325.                     }
  326.         #endif
  327.                 return NULL;
  328.                 }
  329.             }
  330.         }
  331.     
  332.     /* END REAL MALLOC CODE */
  333.  
  334. #if DEBUG_HEAP_INTEGRITY || DEBUG_MAC_MEMORY
  335.     newBlock = (char *) newBlock - sizeof(MemoryBlockHeader);
  336.  
  337. #if DEBUG_HEAP_INTEGRITY
  338.     //    Fill in the blocks header.  This includes adding the block to the used list.
  339.     newBlockHeader = (MemoryBlockHeader *)newBlock;
  340.  
  341.     newBlockHeader->blockSize = blockSize;
  342.     newBlockHeader->headerTag = kUsedBlockHeaderTag;
  343.  
  344.     newBlockHeader->next = gFirstAllocatedBlock;
  345.     newBlockHeader->prev = NULL;    
  346.  
  347.     if (gFirstAllocatedBlock != NULL)
  348.         gFirstAllocatedBlock->prev = newBlockHeader;
  349.     else
  350.         gLastAllocatedBlock = newBlockHeader;
  351.     gFirstAllocatedBlock = newBlockHeader;
  352.         
  353.     //    Fill in the trailer
  354.     newBlockTrailer = (MemoryBlockTrailer *)((char *)newBlock + newCompositeSize - sizeof(MemoryBlockTrailer));
  355.     newBlockTrailer->trailerTag = kUsedBlockTrailerTag;
  356.     
  357.     //    Fill with the used memory pattern
  358.     if (gFillUsedBlocksWithPattern)
  359.         memset((char *)newBlock + sizeof(MemoryBlockHeader), kUsedMemoryFillPattern, blockSize);
  360. #endif
  361.  
  362. #if DEBUG_MAC_MEMORY && GENERATINGPOWERPC
  363.     GetCurrentNativeStackTrace ( stackCrawl );
  364.  
  365. #if TRACK_EACH_ALLOCATOR
  366.     EnableAllocationSet ( whichAllocator->root->set );
  367.     TrackItem ( newBlock, blockSize, 0, kMallocBlock, stackCrawl );
  368.     DisableAllocationSet ( whichAllocator->root->set );
  369. #elif !DEBUG_DONT_TRACK_MALLOC
  370.     TrackItem ( newBlock, blockSize, 0, kMallocBlock, stackCrawl );
  371. #endif
  372.  
  373. #endif
  374.     
  375.     return (void *)((char *)newBlock + sizeof(MemoryBlockHeader));
  376. #else
  377.     return newBlock;
  378. #endif
  379. }
  380.  
  381. void free(void *deadBlock)
  382. {
  383.     MemoryBlockHeader            *deadBlockHeader;
  384. #if DEBUG_HEAP_INTEGRITY
  385.     MemoryBlockTrailer            *deadBlockTrailer;
  386. #endif
  387. #if DEBUG_HEAP_INTEGRITY || STATS_MAC_MEMORY
  388.     size_t                        deadBlockSize;    
  389. #endif
  390.     char                        *deadBlockBase;
  391.     FreeMemoryBlockDescriptor    *descriptor;
  392.     
  393. #if DEBUG_HEAP_INTEGRITY
  394.     if (gVerifyHeapOnEveryFree)
  395.         VerifyMallocHeapIntegrity();
  396. #endif
  397.         
  398.     if (deadBlock == NULL)
  399.         return;
  400.     
  401.     deadBlockBase = ((char *)deadBlock - sizeof(MemoryBlockHeader));
  402.  
  403.     deadBlockHeader = (MemoryBlockHeader *)deadBlockBase;
  404.  
  405. #if DEBUG_HEAP_INTEGRITY || STATS_MAC_MEMORY
  406.     deadBlockSize = deadBlockHeader->blockSize;
  407. #endif
  408. #if DEBUG_HEAP_INTEGRITY
  409.     deadBlockTrailer = (MemoryBlockTrailer *)(deadBlockBase + deadBlockSize + sizeof(MemoryBlockHeader));
  410. #endif
  411.     
  412. #if STATS_MAC_MEMORY
  413.     if (deadBlockSize >= 1024)
  414.         deadBlockSize = 1024;
  415.     gSmallAllocationActiveCountTable[deadBlockSize]--;
  416. #endif
  417.     
  418. #if DEBUG_HEAP_INTEGRITY
  419.     if (deadBlockHeader->headerTag == kFreeBlockHeaderTag) {
  420.         DebugStr("\pfastmem: double dispose of malloc block");
  421.         return;
  422.     }
  423.     else
  424.         if ((deadBlockHeader->headerTag != kUsedBlockHeaderTag) || (deadBlockTrailer->trailerTag != kUsedBlockTrailerTag)) {
  425.             DebugStr("\pfastmem: attempt to dispose illegal block");
  426.             return;
  427.         }
  428.     
  429.     //    Remove the block from the list of used blocks.
  430.     
  431.     if (deadBlockHeader->next != NULL)
  432.         deadBlockHeader->next->prev = deadBlockHeader->prev;
  433.     else
  434.         gLastAllocatedBlock = deadBlockHeader->prev;
  435.         
  436.     if (deadBlockHeader->prev != NULL)
  437.         deadBlockHeader->prev->next = deadBlockHeader->next;
  438.     else
  439.         gFirstAllocatedBlock = deadBlockHeader->next;
  440.     
  441.     //    Change the header and tailer tags to be the free ones.
  442.     
  443.     deadBlockHeader->headerTag = kFreeBlockHeaderTag;
  444.     deadBlockTrailer->trailerTag = kFreeBlockTrailerTag;
  445. #endif
  446.  
  447. #if DEBUG_MAC_MEMORY
  448.     ReleaseItem ( deadBlockBase );
  449. #endif
  450.  
  451. #if DEBUG_HEAP_INTEGRITY
  452.     //    Fill with the free memory pattern
  453.     if (gFillFreeBlocksWithPattern)
  454.         memset(deadBlock, kFreeMemoryFillPattern, deadBlockSize);
  455. #endif
  456.  
  457.     descriptor = deadBlockHeader->blockFreeRoutine;
  458.     
  459. #if DEBUG_MAC_MEMORY || DEBUG_HEAP_INTEGRITY
  460.     if (!gDontActuallyFreeMemory)
  461.         {
  462.         (descriptor->freeRoutine)(deadBlock, descriptor->refcon);
  463.         }
  464. #else
  465.     (descriptor->freeRoutine)(deadBlock, descriptor->refcon);
  466. #endif
  467. }
  468.  
  469. size_t memsize ( void * block )
  470. {
  471.     MemoryBlockHeader            *blockHeader;
  472. #if DEBUG_HEAP_INTEGRITY
  473.     MemoryBlockTrailer            *blockTrailer;
  474.     size_t                        blockSize;    
  475. #endif
  476.     char                        *blockBase;
  477.     FreeMemoryBlockDescriptor    *descriptor;
  478.             
  479.     if (block == NULL)
  480.         return 0;
  481.     
  482.     blockBase = ((char *)block - sizeof(MemoryBlockHeader));
  483.     blockHeader = (MemoryBlockHeader *)blockBase;
  484.  
  485. #if DEBUG_HEAP_INTEGRITY
  486.     // make sure we're looking at a real block
  487.     blockSize = blockHeader->blockSize;
  488.     blockTrailer = (MemoryBlockTrailer *)(blockBase + blockSize + sizeof(MemoryBlockHeader));
  489.     
  490.     if (blockHeader->headerTag == kFreeBlockHeaderTag) {
  491.         DebugStr("\pfastmem: attempt to size free block");
  492.         return 0;
  493.     }
  494.     else
  495.         if ((blockHeader->headerTag != kUsedBlockHeaderTag) || (blockTrailer->trailerTag != kUsedBlockTrailerTag)) {
  496.             DebugStr("\pfastmem: attempt to size illegal block");
  497.             return 0;
  498.         }
  499. #endif
  500.  
  501.     descriptor = blockHeader->blockFreeRoutine;
  502.     return (descriptor->sizeRoutine)(block, descriptor->refcon);
  503. }
  504.  
  505.  
  506. void memtotal ( size_t blockSize, FreeMemoryStats * stats )
  507. {
  508.     AllocMemoryBlockDescriptor *    whichAllocator;
  509.  
  510.     /* which allocator should we use? */
  511.     if (blockSize <= kMaxTableAllocatedBlockSize)
  512.         {
  513.         whichAllocator = gFastMemSmallSizeAllocators + ((blockSize + 3) >> 2);
  514.         }
  515.     else
  516.         {
  517.         /* large blocks come out of entry 0 */
  518.         whichAllocator = &gFastMemSmallSizeAllocators[ 0 ];
  519.         }
  520.     
  521.     whichAllocator->heapFreeSpaceRoutine ( blockSize, stats, whichAllocator->root );
  522. }
  523.  
  524. //##############################################################################
  525. //##############################################################################
  526. #pragma mark -
  527. #pragma mark realloc AND calloc
  528.  
  529. void* reallocSmaller(void* block, size_t newSize)
  530. {
  531. #pragma unused (newSize)
  532.  
  533.     // This actually doesn't reclaim memory!
  534.     return block;
  535. }
  536.  
  537. void* realloc(void* block, size_t newSize)
  538. {
  539.     void         *newBlock = NULL;    
  540.     UInt8        tryAgain = true;
  541.     
  542.     newBlock = malloc(newSize);
  543.     
  544.     if (newBlock != NULL) {    
  545.         BlockMoveData(block, newBlock, newSize);
  546.         free(block);
  547.     }
  548.  
  549.     return newBlock;
  550. }
  551.  
  552. void *calloc(size_t nele, size_t elesize)
  553. {
  554.     char         *newBlock = NULL;
  555.     UInt8        tryAgain = true;
  556.     size_t        totalSize = nele * elesize;
  557.  
  558.     newBlock = (char *) malloc(totalSize);
  559.  
  560.     if (newBlock != NULL)
  561.         memset(newBlock, 0, totalSize);
  562.  
  563.     return newBlock;
  564. }
  565.  
  566.  
  567. //##############################################################################
  568. //##############################################################################
  569. #pragma mark -
  570. #pragma mark DEBUG MEMORY UTILS
  571.  
  572. #if STATS_MAC_MEMORY
  573.  
  574. FILE     *statsFile = NULL;
  575.  
  576. void DumpCurrentMemoryStatistics(char *operation)
  577. {
  578.     UInt32    count;
  579.     
  580.     if (statsFile == NULL)
  581.         statsFile = fopen("stats", "w");
  582.     
  583.     fprintf(statsFile, "%s\n", operation);
  584.     fprintf(statsFile, "Total Allocations\n");
  585.  
  586.     for (count = 0; count < 1025; count++)
  587.         fprintf(statsFile, "%ld\n", gSmallAllocationTotalCountTable[count]);
  588.  
  589.     fprintf(statsFile, "Current Allocation Allocations\n");
  590.  
  591.     for (count = 0; count < 1025; count++)
  592.         fprintf(statsFile, "%ld\n", gSmallAllocationActiveCountTable[count]);
  593.  
  594. }
  595.  
  596. #endif
  597.  
  598.  
  599. #if DEBUG_HEAP_INTEGRITY
  600.  
  601. extern void VerifyMallocHeapIntegrity()
  602. {
  603.     MemoryBlockHeader    *currentBlock = gFirstAllocatedBlock;
  604.  
  605.     //    Walk the used block list, checking all of the headers.
  606.  
  607.     while (currentBlock != NULL) {
  608.     
  609.         MemoryBlockTrailer    *trailer;
  610.         
  611.         trailer = (MemoryBlockTrailer *)((char *)currentBlock + sizeof(MemoryBlockHeader) + currentBlock->blockSize);
  612.     
  613.         if ((currentBlock->headerTag != kUsedBlockHeaderTag) || (trailer->trailerTag != kUsedBlockTrailerTag))
  614.             DebugStr("\pfastmem: malloc heap is corrupt!");
  615.         
  616.         currentBlock = currentBlock->next;
  617.     
  618.     }
  619.     
  620. }
  621.  
  622. #endif
  623.  
  624. #if STATS_MAC_MEMORY
  625. void PrintEfficiency(PRFileHandle file, UInt32 current, UInt32 total)
  626. {    
  627.     UInt32     efficiency = current * 1000 / total;
  628.     UInt32    efficiencyLow = efficiency / 10;
  629.     char    string[ 256 ];
  630.     
  631.     efficiency = efficiency/10;
  632.     
  633.     sprintf(string, "%ld.%ld", efficiency, efficiencyLow);
  634.     WriteString ( file, string );
  635. }
  636. #endif
  637.  
  638. #if DEBUG_HEAP_INTEGRITY
  639. static void TagReferencedBlocks(void)
  640. {
  641.     char *start = (char *) ApplicationZone();
  642.     char *end = (char *) GetApplLimit();
  643.     
  644.     char *comb = start;
  645.     
  646.     while (comb < end) {
  647.     
  648.         MemoryBlockHeader *curCandidate = (MemoryBlockHeader *) comb;
  649.         
  650.         if (curCandidate->headerTag == kFreeBlockHeaderTag || 
  651.             curCandidate->headerTag == kUsedBlockHeaderTag ||
  652.             curCandidate->headerTag == kRefdBlockHeaderTag) {
  653.             
  654.             // we are pointing at a block header            
  655.             // we don't want to consider the next or prev structure members
  656.             // therefore, skip ahead 8 bytes = 2 * sizeof(MemoryBlockHeader *)
  657.                         
  658.             comb += 8;
  659.             
  660.         } else if ((char *) curCandidate->next > start &&
  661.                 (char *) curCandidate->next < end) {
  662.                 
  663.             MemoryBlockHeader *referencedBlock;
  664.             referencedBlock = (MemoryBlockHeader *) ((char *) curCandidate->next - sizeof(MemoryBlockHeader));
  665.                 
  666.             if (referencedBlock->headerTag == kUsedBlockHeaderTag) {
  667.                     
  668.                 // Bingo!!
  669.                 // Marked the referenced block as being referenced.
  670.                 // skip ahead 4 bytes    (or should we be conservative and just skip 2 bytes?)
  671.                 
  672.                 referencedBlock->headerTag = kRefdBlockHeaderTag;    // TODO: insert kRefdBlockTrailerTag as well
  673.                 comb += 4;
  674.                 
  675.             } else {
  676.             
  677.                 // False alarm
  678.                 // it looked like a pointer, but it didn't point to the beginning of a valid used block.
  679.                 // move forward two bytes and look some more
  680.                 
  681.                 comb += 2;
  682.             }
  683.                 
  684.         } else {
  685.         
  686.             // we aren't looking at anything interesting
  687.             // move forward two bytes and look some more.
  688.             
  689.             comb += 2;
  690.         }
  691.         
  692.     }
  693.     
  694. }
  695. #endif
  696.  
  697. #if STATS_MAC_MEMORY || DEBUG_MAC_MEMORY
  698. static void PrintHexNumber( char * string, UInt32 hexNumber )
  699. {
  700.     char        hexString[11];
  701.     char        hexMap[] = "0123456789ABCDEF";
  702.     long        digits = 8;
  703.         
  704.     *string = 0;
  705.     hexString[0] = '0';
  706.     hexString[1] = 'x';
  707.     
  708.     while (digits) {
  709.         hexString[digits + 1] = *((hexNumber & 0x0F) + hexMap);
  710.         hexNumber = hexNumber >> 4;
  711.         digits--;
  712.     }
  713.     hexString[10] = 0;
  714.     
  715.     strcat ( string, hexString );
  716. }
  717. #endif
  718.  
  719. #if STATS_MAC_MEMORY
  720. static void WriteString ( PRFileHandle file, char * string )
  721. {
  722.     long    len;
  723.     long    bytesWritten;
  724.     
  725.     len = strlen ( string );
  726.     if ( len >= 1024 ) Debugger();
  727.     bytesWritten = _OS_WRITE ( file, string, len );
  728.     PR_ASSERT(bytesWritten == len);
  729. }
  730. #endif
  731.  
  732. void DumpMemoryStats(void)
  733. {
  734.  
  735. #if STATS_MAC_MEMORY
  736.  
  737.     UInt32            currentItem;
  738.     char            hexString[11];
  739.     char            outString[ 1024 ];
  740.     PRFileHandle    outFile;
  741.     
  742.     outFile = PR_OpenFile ( "MemoryStats.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644 );
  743.     if ( outFile == NULL )
  744.         {
  745.         return;
  746.         }
  747.  
  748.     sprintf(outString, "********************************************************************************\n");    WriteString ( outFile, outString );
  749.     sprintf(outString, "********************************************************************************\n");    WriteString ( outFile, outString );
  750.     sprintf(outString, "USAGE REPORT (MALLOC HEAP)\n");                                                            WriteString ( outFile, outString );
  751.     sprintf(outString, "********************************************************************************\n");    WriteString ( outFile, outString );
  752.     sprintf(outString, "********************************************************************************\n");    WriteString ( outFile, outString );
  753.     sprintf(outString, "TYPE      BLOCKS (A)  BLOCKS (U)  BLOCKS (F)  MEMORY (A)  MEMORY (U)  EFFICIENCY\n");    WriteString ( outFile, outString );
  754.     sprintf(outString, "----      ----------  ----------  ----------  ----------  ----------  ----------\n");    WriteString ( outFile, outString );
  755.     sprintf(outString, "FIXED   ");                                                                            WriteString ( outFile, outString );
  756.     PrintHexNumber(hexString, gTotalFixedSizeBlocksAllocated);
  757.     sprintf(outString, "%s  ", hexString);                                                                        WriteString ( outFile, outString );
  758.     PrintHexNumber(hexString, gTotalFixedSizeBlocksUsed);
  759.     sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  760.     PrintHexNumber(hexString, gTotalFixedSizeBlocksAllocated - gTotalFixedSizeBlocksUsed);
  761.     sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  762.     PrintHexNumber(hexString, gTotalFixedSizeAllocated);
  763.     sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  764.     PrintHexNumber(hexString, gTotalFixedSizeUsed);
  765.     sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  766.     PrintEfficiency(outFile, gTotalFixedSizeBlocksUsed, gTotalFixedSizeBlocksAllocated);
  767.     sprintf(outString, "/"); WriteString ( outFile, outString );
  768.     PrintEfficiency(outFile, gTotalFixedSizeUsed, gTotalFixedSizeAllocated);
  769.     sprintf(outString, "  \n");     WriteString ( outFile, outString );
  770.     sprintf(outString, "HEAP      "); WriteString ( outFile, outString );
  771.     PrintHexNumber(hexString, 0); WriteString ( outFile, outString );
  772.     sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  773.     PrintHexNumber(hexString, gTotalSmallHeapBlocksUsed);
  774.     sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  775.     PrintHexNumber(hexString, 0);
  776.     sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  777.     PrintHexNumber(hexString, gTotalSmallHeapAllocated);
  778.     sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  779.     PrintHexNumber(hexString, gTotalSmallHeapUsed);
  780.     sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  781.     PrintEfficiency(outFile, gTotalSmallHeapUsed, gTotalSmallHeapAllocated);
  782.     sprintf(outString, "  \nTotal efficiency: "); WriteString ( outFile, outString );
  783.     PrintEfficiency(outFile, gTotalSmallHeapUsed + gTotalFixedSizeUsed, 
  784.         gTotalSmallHeapAllocated + gTotalFixedSizeAllocated);
  785.     sprintf(outString, "  \n");     WriteString ( outFile, outString );
  786.     sprintf(outString, "********************************************************************************\n");     WriteString ( outFile, outString );
  787.     sprintf(outString, "********************************************************************************\n");     WriteString ( outFile, outString );
  788.     sprintf(outString, "BLOCK DISTRIBUTION (MALLOC HEAP: ACTIVE)\n"); WriteString ( outFile, outString );
  789.     sprintf(outString, "********************************************************************************\n");     WriteString ( outFile, outString );
  790.     sprintf(outString, "********************************************************************************\n"); WriteString ( outFile, outString );
  791.     sprintf(outString, "SIZE      +0x00       +0x01       +0x02      +0x03        TOTAL\n"); WriteString ( outFile, outString );
  792.     sprintf(outString, "----      ----------  ----------  ----------  ----------  ----------\n"); WriteString ( outFile, outString );
  793.     
  794.     for (currentItem = 0; currentItem < 64; currentItem++) {
  795.         PrintHexNumber(hexString, currentItem * 4);
  796.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  797.         PrintHexNumber(hexString, gSmallAllocationActiveCountTable[currentItem * 4]);
  798.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  799.         PrintHexNumber(hexString, gSmallAllocationActiveCountTable[currentItem * 4 + 1]);
  800.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  801.         PrintHexNumber(hexString, gSmallAllocationActiveCountTable[currentItem * 4 + 2]);
  802.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  803.         PrintHexNumber(hexString, gSmallAllocationActiveCountTable[currentItem * 4 + 3]);
  804.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  805.         PrintHexNumber(hexString, gSmallAllocationActiveCountTable[currentItem * 4] + 
  806.             gSmallAllocationActiveCountTable[currentItem * 4 + 1] +
  807.             gSmallAllocationActiveCountTable[currentItem * 4 + 2] +
  808.             gSmallAllocationActiveCountTable[currentItem * 4 + 3]);
  809.         sprintf(outString, "\n");     WriteString ( outFile, outString );
  810.     }
  811.     sprintf(outString, "Blocks Over 1K:"); WriteString ( outFile, outString );
  812.     PrintHexNumber(hexString, gSmallAllocationActiveCountTable[1024]);     WriteString ( outFile, hexString );
  813.     sprintf(outString, "\n");     WriteString ( outFile, outString );
  814.     sprintf(outString, "********************************************************************************\n");     WriteString ( outFile, outString );
  815.     sprintf(outString, "********************************************************************************\n");     WriteString ( outFile, outString );
  816.     sprintf(outString, "BLOCK DISTRIBUTION (MALLOC HEAP: MAX)\n"); WriteString ( outFile, outString );
  817.     sprintf(outString, "********************************************************************************\n");     WriteString ( outFile, outString );
  818.     sprintf(outString, "********************************************************************************\n"); WriteString ( outFile, outString );
  819.     sprintf(outString, "SIZE      +0x00       +0x01       +0x02      +0x03        TOTAL\n"); WriteString ( outFile, outString );
  820.     sprintf(outString, "----      ----------  ----------  ----------  ----------  ----------\n"); WriteString ( outFile, outString );
  821.     
  822.     for (currentItem = 0; currentItem < 64; currentItem++) {
  823.         PrintHexNumber(hexString, currentItem * 4);
  824.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  825.         PrintHexNumber(hexString, gSmallAllocationMaxCountTable[currentItem * 4]);
  826.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  827.         PrintHexNumber(hexString, gSmallAllocationMaxCountTable[currentItem * 4 + 1]);
  828.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  829.         PrintHexNumber(hexString, gSmallAllocationMaxCountTable[currentItem * 4 + 2]);
  830.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  831.         PrintHexNumber(hexString, gSmallAllocationMaxCountTable[currentItem * 4 + 3]);
  832.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  833.         PrintHexNumber(hexString, gSmallAllocationMaxCountTable[currentItem * 4] + 
  834.             gSmallAllocationMaxCountTable[currentItem * 4 + 1] +
  835.             gSmallAllocationMaxCountTable[currentItem * 4 + 2] +
  836.             gSmallAllocationMaxCountTable[currentItem * 4 + 3]);
  837.         sprintf(outString, "\n");     WriteString ( outFile, outString );
  838.     }
  839.     sprintf(outString, "Blocks Over 1K:"); WriteString ( outFile, outString );
  840.     PrintHexNumber(hexString, gSmallAllocationMaxCountTable[1024]);     WriteString ( outFile, hexString );
  841.     sprintf(outString, "\n");     WriteString ( outFile, outString );
  842.     sprintf(outString, "********************************************************************************\n");     WriteString ( outFile, outString );
  843.     sprintf(outString, "********************************************************************************\n");     WriteString ( outFile, outString );
  844.     sprintf(outString, "BLOCK DISTRIBUTION (MALLOC HEAP: TOTAL)\n"); WriteString ( outFile, outString );
  845.     sprintf(outString, "********************************************************************************\n");     WriteString ( outFile, outString );
  846.     sprintf(outString, "********************************************************************************\n"); WriteString ( outFile, outString );
  847.     sprintf(outString, "SIZE        +0x00       +0x01       +0x02      +0x03        TOTAL\n"); WriteString ( outFile, outString );
  848.     sprintf(outString, "----        ----------  ----------  ----------  ----------  ----------\n"); WriteString ( outFile, outString );
  849.     
  850.     for (currentItem = 0; currentItem < 64; currentItem++) {
  851.         PrintHexNumber(hexString, currentItem * 4);
  852.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  853.         PrintHexNumber(hexString, gSmallAllocationTotalCountTable[currentItem * 4]);
  854.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  855.         PrintHexNumber(hexString, gSmallAllocationTotalCountTable[currentItem * 4 + 1]);
  856.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  857.         PrintHexNumber(hexString, gSmallAllocationTotalCountTable[currentItem * 4 + 2]);
  858.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  859.         PrintHexNumber(hexString, gSmallAllocationTotalCountTable[currentItem * 4 + 3]);
  860.         sprintf(outString, "%s  ", hexString);     WriteString ( outFile, outString );
  861.         PrintHexNumber(hexString, gSmallAllocationTotalCountTable[currentItem * 4] + 
  862.             gSmallAllocationTotalCountTable[currentItem * 4 + 1] +
  863.             gSmallAllocationTotalCountTable[currentItem * 4 + 2] +
  864.             gSmallAllocationTotalCountTable[currentItem * 4 + 3]);
  865.         sprintf(outString, "\n");     WriteString ( outFile, outString );
  866.     }
  867.     sprintf(outString, "Blocks Over 1K:"); WriteString ( outFile, outString );
  868.     PrintHexNumber(hexString, gSmallAllocationTotalCountTable[1024]);
  869.     sprintf(outString, "%s\n", hexString);     WriteString ( outFile, outString );
  870.  
  871. #endif
  872. }
  873.  
  874.  
  875. //##############################################################################
  876. //##############################################################################
  877. #pragma mark -
  878. #pragma mark LARGE BLOCK ALLOCATOR
  879.  
  880. FreeMemoryBlockDescriptor    StandardFreeDescriptor = { &LargeBlockFree, 0 };
  881.  
  882. #define    LARGE_BLOCK_FREE(b)        ((b)->prev == NULL)
  883. #define    LARGE_BLOCK_SIZE(b)        ((UInt32) (b)->next - (UInt32) (b))
  884. #define    LARGE_BLOCK_OVERHEAD    (sizeof(LargeBlockHeader) + MEMORY_BLOCK_TAILER_SIZE)
  885. #define    LARGE_BLOCK_INC(b)        ((LargeBlockHeader *) ((UInt32) (b) + LARGE_BLOCK_OVERHEAD))
  886.  
  887. void *LargeBlockAlloc(size_t blockSize, void *refcon)
  888. {
  889.     LargeBlockAllocationRoot *    root = (LargeBlockAllocationRoot *)refcon;
  890.     LargeBlockAllocationChunk *    chunk = (LargeBlockAllocationChunk *) root->header.firstChunk;
  891.     LargeBlockHeader *            blockHeader;
  892.     LargeBlockHeader *            prevBlock;
  893.     LargeBlockHeader *            freeBlock;
  894.     size_t                        freeBlockSize;
  895.     size_t                        allocSize;
  896. #if DEBUG_MAC_ALLOCATORS && DEBUG_MAC_MEMORY
  897.     void *                        stackCrawl[ kStackDepth ];
  898.     
  899.     GetCurrentStackTrace(stackCrawl);
  900. #endif
  901.  
  902.     /* round the block size up to a multiple of four and add space for the header and trailer */
  903.     allocSize = ( ( blockSize + 3 ) & ~3 ) + LARGE_BLOCK_OVERHEAD;
  904.     
  905.     /* find an allocation chunk that can hold our block */
  906.     while ( chunk != NULL )
  907.         {
  908.         /* scan through the blocks in this chunk looking for a big enough free block */
  909.         /* we never allocate the head block */
  910.         prevBlock = chunk->head;
  911.         blockHeader = prevBlock->next;
  912.         
  913.         do
  914.             {
  915.             if ( LARGE_BLOCK_FREE(blockHeader) )
  916.                 {
  917.                 freeBlockSize = LARGE_BLOCK_SIZE(blockHeader);
  918.                 if ( freeBlockSize >= allocSize )
  919.                     {
  920.                     break;
  921.                     }
  922.                 }
  923.             
  924.             prevBlock = blockHeader;
  925.             blockHeader = blockHeader->next;
  926.             }
  927.         while ( blockHeader != NULL );
  928.         
  929.         /* if we found a block, go use it */
  930.         if ( blockHeader != NULL )
  931.             {
  932.             break;
  933.             }
  934.         
  935.         /* otherwise, go look at the next chunk */
  936.         chunk = (LargeBlockAllocationChunk *) chunk->header.next;
  937.         }
  938.     
  939.     if ( blockHeader != NULL )
  940.         {
  941.         chunk->header.usedBlocks++;
  942.     
  943. #if DEBUG_MAC_ALLOCATORS && DEBUG_MAC_MEMORY
  944.         EnableAllocationSet ( gLargeBlockAllocatorSet );
  945.         TrackItem ( blockHeader, allocSize, 0, kPointerBlock, stackCrawl );
  946.         DisableAllocationSet ( gLargeBlockAllocatorSet );
  947. #endif
  948.         
  949.         /* is there space at the end of this block for a free block? */
  950.         if ( ( freeBlockSize - allocSize ) > LARGE_BLOCK_OVERHEAD )
  951.             {
  952.             freeBlock = (LargeBlockHeader *) ( (char *) blockHeader + allocSize );
  953.             freeBlock->prev = NULL;
  954.             freeBlock->next = blockHeader->next;
  955.             freeBlock->next->prev = freeBlock;
  956.             blockHeader->next = freeBlock;
  957.             }
  958.         
  959.         /* allocate this block */
  960.         blockHeader->size = blockSize;
  961.         blockHeader->prev = prevBlock;
  962.         blockHeader->header.blockFreeRoutine = &chunk->header.freeDescriptor;
  963.         
  964.         chunk->totalFree -= LARGE_BLOCK_SIZE(blockHeader);
  965.         
  966.         return (void *)((char *)blockHeader + sizeof(LargeBlockHeader));
  967.         }
  968.     else
  969.         {
  970.         return NULL;
  971.         }    
  972. }
  973.  
  974.  
  975. void LargeBlockFree(void *block, void *refcon)
  976. {
  977.     LargeBlockAllocationChunk *    chunk = (LargeBlockAllocationChunk *) refcon;
  978.     LargeBlockAllocationRoot *    root = (LargeBlockAllocationRoot *) chunk->header.root;
  979.     LargeBlockHeader *            blockHeader;
  980.     LargeBlockHeader *            prev;
  981.     LargeBlockHeader *            next;
  982.     
  983.     blockHeader = (LargeBlockHeader *) ((char *)block - sizeof(LargeBlockHeader));
  984.  
  985. #if DEBUG_MAC_ALLOCATORS && DEBUG_MAC_MEMORY
  986.     EnableAllocationSet ( gLargeBlockAllocatorSet );
  987.     ReleaseItem ( blockHeader );
  988.     DisableAllocationSet ( gLargeBlockAllocatorSet );
  989. #endif
  990.     
  991.     /* we might want to coalese this block with it's prev or next neighbor */
  992.     prev = blockHeader->prev;
  993.     next = blockHeader->next;
  994.  
  995.     if ( LARGE_BLOCK_FREE(prev) )
  996.         {
  997.         chunk->totalFree -= LARGE_BLOCK_SIZE(prev);
  998.         prev->next = blockHeader->next;
  999.         blockHeader = prev;
  1000.         
  1001.         if ( LARGE_BLOCK_FREE(next) )
  1002.             {
  1003.             chunk->totalFree -= LARGE_BLOCK_SIZE(next);
  1004.             blockHeader->next = next->next;
  1005.             next->next->prev = blockHeader;
  1006.             }
  1007.         else
  1008.             {
  1009.             next->prev = blockHeader;
  1010.             }
  1011.         }
  1012.     else
  1013.     if ( LARGE_BLOCK_FREE(next) )
  1014.         {
  1015.         chunk->totalFree -= LARGE_BLOCK_SIZE(next);
  1016.         blockHeader->next = next->next;
  1017.         next->next->prev = blockHeader;
  1018.         }
  1019.     
  1020.     blockHeader->prev = NULL;
  1021.  
  1022.     chunk->totalFree += LARGE_BLOCK_SIZE(blockHeader);
  1023.     
  1024.     --chunk->header.usedBlocks;
  1025.     
  1026.     // if this chunk is completely empty and it's not the first chunk then free it
  1027.     if ( chunk->header.usedBlocks == 0 && root->header.firstChunk != (SubHeapAllocationChunk *) chunk )
  1028.         {
  1029.         FreeSubHeap ( &root->header, &chunk->header );
  1030.         }
  1031. }
  1032.  
  1033.  
  1034. SubHeapAllocationChunk * LargeBlockAllocChunk ( size_t blockSize, void * refcon )
  1035. {
  1036.     LargeBlockAllocationRoot *    root = refcon;
  1037.     UInt32                        bestHeapSize;
  1038.     UInt32                        smallestHeapSize;
  1039.     Boolean                        useTemp;
  1040.     LargeBlockAllocationChunk *    chunk;
  1041.     LargeBlockHeader *            freeBlock;
  1042. #if DEBUG_ALLOCATION_CHUNKS && DEBUG_MAC_MEMORY
  1043.     void *                        stackCrawl[ kStackDepth ];
  1044.     
  1045.     GetCurrentStackTrace(stackCrawl);
  1046. #endif
  1047.     
  1048.     useTemp = root->header.firstChunk != NULL;
  1049.     
  1050.     if ( useTemp )
  1051.         {
  1052.         bestHeapSize = root->idealTempChunkSize;
  1053.         smallestHeapSize = root->smallestTempChunkSize;
  1054.         }
  1055.     else
  1056.         {
  1057.         /*
  1058.          * since we use total free memory here rather than the size of the biggest block, there is a slim
  1059.          * chance this operation could fail. our heap should be very unfragmented at this point (we get called
  1060.          * very early in the boot sequence) so this should be safe.
  1061.          */
  1062.         smallestHeapSize = bestHeapSize = ( root->baseChunkPercentage * FreeMem() ) / 100;
  1063.         }
  1064.     
  1065.     /* make sure that the heap will be big enough to accomodate our block (we have at least three block headers in a heap) */
  1066.     blockSize += 3 * LARGE_BLOCK_OVERHEAD;
  1067.     if ( smallestHeapSize < blockSize )
  1068.         {
  1069.         smallestHeapSize = blockSize;
  1070.         }
  1071.     
  1072.     if ( bestHeapSize < blockSize )
  1073.         {
  1074.         bestHeapSize = blockSize;
  1075.         }
  1076.     
  1077.     do    {
  1078.         chunk = (LargeBlockAllocationChunk *) AllocateSubHeap ( &root->header, bestHeapSize + sizeof(LargeBlockAllocationChunk),
  1079.             useTemp );
  1080.         
  1081.         /* if we failed, then try a smaller heap */
  1082.         if ( chunk == NULL )
  1083.             {
  1084.             bestHeapSize -= 64 * 1024;
  1085.             }
  1086.         }
  1087.     while ( ( chunk == NULL ) && ( bestHeapSize >= smallestHeapSize ) );
  1088.     
  1089.     /* if that failed, then try allocating the smallest chunk out of the application heap */
  1090.     /* call the fe low memory proc as well, cuz we're running out jim */
  1091.     if ( ( chunk == NULL ) && useTemp )
  1092.         {
  1093.         chunk = (LargeBlockAllocationChunk *) AllocateSubHeap ( &root->header, smallestHeapSize + sizeof(LargeBlockAllocationChunk),
  1094.             false );
  1095.         
  1096.         CallFE_LowMemory();
  1097.         }
  1098.         
  1099.     if ( chunk != NULL )
  1100.         {
  1101. #if DEBUG_ALLOCATION_CHUNKS && DEBUG_MAC_MEMORY
  1102.         EnableAllocationSet ( gLargeBlockAllocatorSet );
  1103.         TrackItem ( chunk, bestHeapSize + sizeof(LargeBlockAllocationChunk), 0, kPointerBlock, stackCrawl );
  1104.         DisableAllocationSet ( gLargeBlockAllocatorSet );
  1105. #endif
  1106.         
  1107.         // mark how much we can actually store in the heap
  1108.         chunk->header.heapSize = bestHeapSize - 3 * sizeof(LargeBlockHeader);
  1109.  
  1110.         chunk->header.freeDescriptor.freeRoutine = LargeBlockFree;
  1111.         chunk->header.freeDescriptor.sizeRoutine = LargeBlockSize;
  1112.         chunk->header.freeDescriptor.refcon = chunk;
  1113.         
  1114.         /* the head block is zero size and is never free */
  1115.         chunk->head->prev = (LargeBlockHeader *) -1L;
  1116.         chunk->head->next = LARGE_BLOCK_INC(chunk->head);
  1117.         
  1118.         /* we have a free block in the middle */
  1119.         freeBlock = LARGE_BLOCK_INC(chunk->head);
  1120.         freeBlock->prev = NULL;
  1121.         freeBlock->next = (LargeBlockHeader *) ( (UInt32) freeBlock + bestHeapSize - 2 * LARGE_BLOCK_OVERHEAD );
  1122.         
  1123.         /* and then a zero sized allcated block at the end */
  1124.         chunk->tail = freeBlock->next;
  1125.         chunk->tail->next = NULL;
  1126.         chunk->tail->prev = freeBlock;
  1127.  
  1128.         chunk->totalFree = LARGE_BLOCK_SIZE(freeBlock);
  1129.         }
  1130.     
  1131.     return &chunk->header;
  1132. }
  1133.  
  1134. size_t LargeBlockSize (void *block, void *refcon)
  1135. {
  1136. #pragma unused(refcon)
  1137.     LargeBlockHeader *            blockHeader;
  1138.         
  1139.     blockHeader = (LargeBlockHeader *) ((char *)block - sizeof(LargeBlockHeader));
  1140.  
  1141.     return blockHeader->size;
  1142. }
  1143.  
  1144. void LargeBlockHeapFree(size_t blockSize, FreeMemoryStats * stats, void * refcon)
  1145. {
  1146. #pragma unused(blockSize, refcon)
  1147.     LargeBlockAllocationRoot *    root = refcon;
  1148.     LargeBlockAllocationChunk *    chunk;
  1149.     uint32                        freeBytes;
  1150.     uint32                        totalBytes;
  1151.     uint32                        maxBlock;
  1152.     uint32                        curBlockSize;
  1153.     LargeBlockHeader *            blockList;
  1154.         
  1155.     freeBytes = 0;
  1156.     maxBlock = 0;
  1157.     totalBytes = 0;
  1158.     
  1159.     chunk = (LargeBlockAllocationChunk *) root->header.firstChunk;
  1160.     while ( chunk != NULL )
  1161.         {
  1162.         /* count up all the free blocks in this chunk */
  1163.         for ( blockList = chunk->head; blockList != NULL; blockList = blockList->next )
  1164.             {
  1165.             if ( LARGE_BLOCK_FREE(blockList) )
  1166.                 {
  1167.                 curBlockSize = LARGE_BLOCK_SIZE(blockList) - LARGE_BLOCK_OVERHEAD;
  1168.                 
  1169.                 freeBytes += curBlockSize;
  1170.                 if ( maxBlock < curBlockSize )
  1171.                     {
  1172.                     maxBlock = curBlockSize;
  1173.                     }
  1174.                 }
  1175.             }
  1176.             
  1177.         totalBytes += chunk->header.heapSize;
  1178.         
  1179.         chunk = (LargeBlockAllocationChunk *) chunk->header.next;
  1180.         }
  1181.         
  1182.     stats->maxBlockSize = maxBlock;
  1183.     stats->totalHeapSize = totalBytes;
  1184.     stats->totalFreeBytes = freeBytes;
  1185. }
  1186.  
  1187. //##############################################################################
  1188. //##############################################################################
  1189. #pragma mark -
  1190. #pragma mark FIXED SIZED ALLOCATOR
  1191.  
  1192. void *FixedSizeAlloc(size_t blockSize, void *refcon)
  1193. {
  1194. #pragma unused (blockSize)
  1195.     FixedSizeAllocationRoot *    root = (FixedSizeAllocationRoot *)refcon;
  1196.     FixedSizeAllocationChunk *    chunk = (FixedSizeAllocationChunk *) root->header.firstChunk;
  1197.     MemoryBlockHeader *            blockHeader;
  1198. #if DEBUG_MAC_ALLOCATORS && DEBUG_MAC_MEMORY
  1199.     void *                        stackCrawl[ kStackDepth ];
  1200.     
  1201.     GetCurrentStackTrace(stackCrawl);
  1202. #endif
  1203.     
  1204.     blockHeader = NULL;
  1205.     
  1206.     //    Try to find an existing chunk with a free block.
  1207.     while ( chunk != NULL )
  1208.         {
  1209.         if ( chunk->freeList != NULL )
  1210.             {
  1211.             break;
  1212.             }
  1213.         
  1214.         chunk = (FixedSizeAllocationChunk *) chunk->header.next;
  1215.         }
  1216.     
  1217.     if ( chunk != NULL )
  1218.         {
  1219.         blockHeader = (MemoryBlockHeader *) chunk->freeList;
  1220.         ++chunk->header.usedBlocks;
  1221.         chunk->freeList = chunk->freeList->next;
  1222.         blockHeader->blockFreeRoutine = &chunk->header.freeDescriptor;
  1223.     
  1224. #if DEBUG_MAC_ALLOCATORS && DEBUG_MAC_MEMORY
  1225.         EnableAllocationSet ( gFixedSizeAllocatorSet );
  1226.         TrackItem ( blockHeader, blockSize, 0, kPointerBlock, stackCrawl );
  1227.         DisableAllocationSet ( gFixedSizeAllocatorSet );
  1228. #endif
  1229. #if STATS_MAC_MEMORY
  1230.         gTotalFixedSizeUsed += root->blockSize;
  1231.         gTotalFixedSizeBlocksUsed++;
  1232. #endif
  1233.         }
  1234.     else
  1235.         {
  1236.         return NULL;
  1237.         }
  1238.  
  1239.     return (void *)((char *)blockHeader + sizeof(MemoryBlockHeader));
  1240.     
  1241. }
  1242.  
  1243. void FixedSizeFree(void *block, void *refcon)
  1244. {
  1245.     FixedMemoryFreeBlockHeader *    blockHeader;
  1246.     FixedSizeAllocationChunk *        chunk;
  1247.     FixedSizeAllocationRoot *        root;
  1248.     
  1249.     //    Find the block header and the chunk
  1250.     
  1251.     blockHeader = (FixedMemoryFreeBlockHeader *)((char *)block - sizeof(MemoryBlockHeader));
  1252.     chunk = (FixedSizeAllocationChunk *) refcon;
  1253.     root = (FixedSizeAllocationRoot *) chunk->header.root;
  1254.  
  1255. #if DEBUG_MAC_ALLOCATORS && DEBUG_MAC_MEMORY
  1256.     EnableAllocationSet ( gFixedSizeAllocatorSet );
  1257.     ReleaseItem ( blockHeader );
  1258.     DisableAllocationSet ( gFixedSizeAllocatorSet );
  1259. #endif
  1260.     
  1261.     // put this block back on the free list
  1262.     blockHeader->next = chunk->freeList;
  1263.     chunk->freeList = blockHeader;
  1264.     chunk->header.usedBlocks--;
  1265.     
  1266.     // if this chunk is completely empty and it's not the first chunk then free it
  1267.     if ( chunk->header.usedBlocks == 0 && root->header.firstChunk != (SubHeapAllocationChunk *) chunk )
  1268.         {
  1269.         FreeSubHeap ( &root->header, &chunk->header );
  1270.         }
  1271.     
  1272.  
  1273. #if STATS_MAC_MEMORY
  1274.     gTotalFixedSizeUsed -= root->blockSize;
  1275.     gTotalFixedSizeBlocksUsed--;
  1276. #endif
  1277.         
  1278. }
  1279.  
  1280. SubHeapAllocationChunk * FixedSizeAllocChunk ( size_t blockSize, void * refcon )
  1281. {
  1282.     FixedSizeAllocationRoot *            root = refcon;
  1283.     UInt32                                chunkSize;
  1284.     FixedSizeAllocationChunk *            chunk;
  1285.     FixedMemoryFreeBlockHeader *        freePtr;
  1286.     FixedMemoryFreeBlockHeader *        nextFree;
  1287.     FixedMemoryFreeBlockHeader *        lastFree;
  1288.     UInt32                                blockCount;
  1289.     UInt32                                numBlocks;
  1290.     Boolean                                useTemp;
  1291. #if DEBUG_ALLOCATION_CHUNKS && DEBUG_MAC_MEMORY
  1292.     void *                                stackCrawl[ kStackDepth ];
  1293.     
  1294.     GetCurrentStackTrace(stackCrawl);
  1295. #endif
  1296.     
  1297.     chunk = NULL;
  1298.     
  1299.     /* if this size doesn't have a root yet, use real mems, otherwise do temp */
  1300.     if ( root->header.firstChunk == NULL )
  1301.         {
  1302.         useTemp = false;
  1303.         numBlocks = root->baseChunkBlockCount;
  1304.         }
  1305.     else
  1306.         {
  1307.         useTemp = true;
  1308.         numBlocks = root->tempChunkBlockCount;
  1309.         }
  1310.         
  1311.     blockSize = root->blockSize + sizeof(MemoryBlockHeader) + MEMORY_BLOCK_TAILER_SIZE;
  1312.     chunkSize = blockSize * numBlocks + sizeof(FixedSizeAllocationChunk);
  1313.     
  1314.     chunk = (FixedSizeAllocationChunk *) AllocateSubHeap ( &root->header, chunkSize, useTemp );
  1315.     
  1316.     if ( chunk != NULL )
  1317.         {
  1318. #if DEBUG_ALLOCATION_CHUNKS && DEBUG_MAC_MEMORY
  1319.         EnableAllocationSet ( gFixedSizeAllocatorSet );
  1320.         TrackItem ( chunk, chunkSize, 0, kPointerBlock, stackCrawl );
  1321.         DisableAllocationSet ( gFixedSizeAllocatorSet );
  1322. #endif
  1323.         chunk->header.freeDescriptor.freeRoutine = FixedSizeFree;
  1324.         chunk->header.freeDescriptor.sizeRoutine = FixedBlockSize;
  1325.         chunk->header.freeDescriptor.refcon = chunk;
  1326. #if STATS_MAC_MEMORY
  1327.         chunk->chunkSize = chunkSize;
  1328.         chunk->numBlocks = numBlocks;
  1329.         
  1330.         gTotalFixedSizeAllocated += chunkSize;
  1331.         gTotalFixedSizeBlocksAllocated += numBlocks;
  1332. #endif
  1333.                     
  1334.         // mark how much we can actually store in the heap
  1335.         chunk->header.heapSize = numBlocks * root->blockSize;
  1336.  
  1337.         /* build the free list for this chunk */
  1338.         blockCount = numBlocks;
  1339.         
  1340.         freePtr = chunk->memory;
  1341.         chunk->freeList = freePtr;
  1342.         
  1343.         do    {
  1344.             lastFree = freePtr;
  1345.             nextFree = (FixedMemoryFreeBlockHeader *) ( (UInt32) freePtr + (UInt32) blockSize );
  1346.             freePtr->next = nextFree;
  1347.             freePtr = nextFree;
  1348.             }
  1349.         while ( --blockCount > 0 );
  1350.         
  1351.         lastFree->next = NULL;
  1352.         }
  1353.     
  1354.     return &chunk->header;
  1355. }
  1356.  
  1357. size_t FixedBlockSize (void *block, void *refcon)
  1358. {
  1359. #pragma unused(block)
  1360.     FixedSizeAllocationChunk *        chunk;
  1361.     FixedSizeAllocationRoot *        root;
  1362.         
  1363.     //    Find the block header and the chunk
  1364.     
  1365.     chunk = (FixedSizeAllocationChunk *) refcon;
  1366.     root = (FixedSizeAllocationRoot *) chunk->header.root;
  1367.     
  1368.     return root->blockSize;
  1369. }
  1370.  
  1371. void FixedBlockHeapFree(size_t blockSize, FreeMemoryStats * stats, void * refcon)
  1372. {
  1373. #pragma unused(blockSize)
  1374.     FixedSizeAllocationRoot *            root = refcon;
  1375.     FixedSizeAllocationChunk *            chunk;
  1376.     uint32                                freeBlocks;
  1377.     uint32                                totalBytes;
  1378.     FixedMemoryFreeBlockHeader *        freeList;
  1379.         
  1380.     freeBlocks = 0;
  1381.     totalBytes = 0;
  1382.     
  1383.     chunk = (FixedSizeAllocationChunk *) root->header.firstChunk;
  1384.     while ( chunk != NULL )
  1385.         {
  1386.         /* count up the free blocks */
  1387.         for ( freeList = chunk->freeList; freeList != NULL; freeList = freeList->next )
  1388.             {
  1389.             ++freeBlocks;
  1390.             }
  1391.         
  1392.         totalBytes += chunk->header.heapSize;
  1393.         
  1394.         chunk = (FixedSizeAllocationChunk *) chunk->header.next;
  1395.         }
  1396.     
  1397.     stats->maxBlockSize = root->blockSize;
  1398.     stats->totalHeapSize = totalBytes;
  1399.     stats->totalFreeBytes = freeBlocks * root->blockSize;
  1400. }
  1401.  
  1402.  
  1403. //##############################################################################
  1404. //##############################################################################
  1405. #pragma mark -
  1406. #pragma mark SMALL HEAP ALLOCATOR
  1407.  
  1408. #define SmallHeapBlockToMemoryPtr(x) ((void *)((Ptr)x + sizeof(SmallHeapBlock)))
  1409. #define MemoryPtrToSmallHeapBlock(x) ((SmallHeapBlock *)((Ptr)x - sizeof(SmallHeapBlock)))
  1410.  
  1411. #define NextSmallHeapBlock(x) ((SmallHeapBlock *)((Ptr)x + (x->blockSize & ~kBlockInUseFlag) + sizeof(SmallHeapBlock) + MEMORY_BLOCK_TAILER_SIZE))
  1412. #define PrevSmallHeapBlock(x) (x->prevBlock)
  1413.  
  1414. #define SmallHeapBlockInUse(x) ((x->blockSize & kBlockInUseFlag) != 0)
  1415. #define SmallHeapBlockNotInUse(x) ((x->blockSize & kBlockInUseFlag) == 0)
  1416.  
  1417. #define TotalSmallHeapBlockUsage(x) ((x->blockSize & ~kBlockInUseFlag) + sizeof(SmallHeapBlock) + MEMORY_BLOCK_TAILER_SIZE)
  1418.  
  1419. #define AddSmallHeapBlockToFreeList(r, x)                                                        \
  1420. {                                                                                                \
  1421.     UInt32                blockSize = x->blockSize & ~kBlockInUseFlag;                            \
  1422.     UInt32                nextBlockBin;                                                            \
  1423.     SmallHeapBlock        *tempBlock;                                                                \
  1424.     x->blockSize = blockSize        ;                                                            \
  1425.     nextBlockBin = (blockSize - kDefaultSmallHeadMinSize) >> 2;                                    \
  1426.     x->info.freeInfo.prevFree = NULL;                                                            \
  1427.     if (blockSize > kMaximumBinBlockSize) {                                                        \
  1428.         tempBlock = r->overflow;                                                                \
  1429.         x->info.freeInfo.nextFree = tempBlock;                                                    \
  1430.         if (tempBlock != NULL)                                                                    \
  1431.             tempBlock->info.freeInfo.prevFree = x;                                                \
  1432.         r->overflow = x;                                                                        \
  1433.     }                                                                                            \
  1434.     else {                                                                                        \
  1435.         tempBlock = r->bins[nextBlockBin];                                                        \
  1436.         x->info.freeInfo.nextFree = tempBlock;                                                    \
  1437.         if (tempBlock != NULL)                                                                    \
  1438.             tempBlock->info.freeInfo.prevFree = x;                                                \
  1439.         r->bins[nextBlockBin] = x;                                                                \
  1440.     }                                                                                            \
  1441. }
  1442.  
  1443. #define RemoveSmallHeapBlockFromFreeList(r, x)                                                    \
  1444. {                                                                                                \
  1445.     SmallHeapBlock        *nextFree,                                                                \
  1446.                         *prevFree;                                                                \
  1447.     UInt32                blockSize = x->blockSize;                                                \
  1448.     UInt32                nextBlockBin;                                                            \
  1449.     x->blockSize |= kBlockInUseFlag;                                                            \
  1450.     nextBlockBin = (blockSize - kDefaultSmallHeadMinSize) >> 2;                                    \
  1451.     nextFree = x->info.freeInfo.nextFree;                                                        \
  1452.     prevFree = x->info.freeInfo.prevFree;                                                        \
  1453.     if (nextFree != NULL)                                                                        \
  1454.         nextFree->info.freeInfo.prevFree = prevFree;                                            \
  1455.     if (prevFree != NULL)                                                                        \
  1456.         prevFree->info.freeInfo.nextFree = nextFree;                                            \
  1457.     else                                                                                        \
  1458.         if (blockSize > kMaximumBinBlockSize)                                                    \
  1459.             r->overflow = nextFree;                                                                \
  1460.         else                                                                                    \
  1461.             r->bins[nextBlockBin] = nextFree;                                                    \
  1462. }
  1463.  
  1464.  
  1465. #if DEBUG_HEAP_INTEGRITY
  1466. void SmallHeapCheck(SmallHeapBlock *fromBlock);
  1467. void SmallHeapCheck(SmallHeapBlock *fromBlock)
  1468. {
  1469.     SmallHeapBlock         *previousBlock = NULL;
  1470.     
  1471.     //    Go to the first block in the list
  1472.     
  1473.     while (fromBlock->prevBlock != NULL)
  1474.         fromBlock = fromBlock->prevBlock;
  1475.     
  1476.     //    Walk the list
  1477.     
  1478.     while (fromBlock) {
  1479.     
  1480.         if (fromBlock->blockSize == 0xFFFFFFFF)
  1481.             break;
  1482.     
  1483.         if (previousBlock != NULL) {
  1484.             if (previousBlock != PrevSmallHeapBlock(fromBlock)) {
  1485.                 DebugStr("\pSmall Heap Corrupt");
  1486.                 break;
  1487.             }
  1488.         }
  1489.         previousBlock = fromBlock;
  1490.         fromBlock = NextSmallHeapBlock(fromBlock);
  1491.     
  1492.     }    
  1493.  
  1494. }
  1495. #endif
  1496.  
  1497. void *SmallHeapAlloc(size_t blockSize, void *refcon)
  1498. {
  1499.     SmallHeapRoot            *heapRoot = (SmallHeapRoot *)refcon;
  1500.     SmallHeapChunk            *chunk = (SmallHeapChunk *) heapRoot->header.firstChunk;
  1501.     UInt32                    startingBinNum,
  1502.                             remainingBins;
  1503.     SmallHeapBlock            **currentBin;
  1504.     SmallHeapBlock            *currentBinValue;
  1505.     SmallHeapBlock            *blockToCarve;
  1506. #if DEBUG_MAC_ALLOCATORS && DEBUG_MAC_MEMORY
  1507.     void *                    stackCrawl[ kStackDepth ];
  1508.     
  1509.     GetCurrentStackTrace(stackCrawl);
  1510. #endif
  1511.  
  1512.     //    Round up allocation to nearest 4 bytes.
  1513.     
  1514.     blockSize = (blockSize + 3) & 0xFFFFFFFC;
  1515.  
  1516. tryAlloc:
  1517.  
  1518.     // walk through all of our chunks, trying to allocate memory from somewhere
  1519.     while ( chunk != NULL )
  1520.         {
  1521.         //    Try to find the best fit in one of the bins.
  1522.         
  1523.         startingBinNum = (blockSize - kDefaultSmallHeadMinSize) >> 2;
  1524.         
  1525.         currentBin = chunk->bins + startingBinNum;
  1526.         currentBinValue = *currentBin;
  1527.             
  1528.         //    If the current bin has something in it,
  1529.         //    then use it for our allocation.
  1530.         
  1531.         if (currentBinValue != NULL) {
  1532.             
  1533.             RemoveSmallHeapBlockFromFreeList(chunk, currentBinValue);
  1534.  
  1535.             currentBinValue->info.inUseInfo.freeProc.blockFreeRoutine = &chunk->header.freeDescriptor;
  1536.  
  1537.     #if STATS_MAC_MEMORY
  1538.             gTotalSmallHeapBlocksUsed++;
  1539.             gTotalSmallHeapUsed += TotalSmallHeapBlockUsage(currentBinValue);
  1540.     #endif
  1541. #if DEBUG_MAC_ALLOCATORS && DEBUG_MAC_MEMORY
  1542.             EnableAllocationSet ( gSmallHeapAllocatorSet );
  1543.             TrackItem ( currentBinValue, blockSize, 0, kPointerBlock, stackCrawl );
  1544.             DisableAllocationSet ( gSmallHeapAllocatorSet );
  1545. #endif
  1546.  
  1547.             return SmallHeapBlockToMemoryPtr(currentBinValue);
  1548.  
  1549.         }
  1550.  
  1551.         //    Otherwise, try to carve up an existing larger block.
  1552.  
  1553.         remainingBins = kDefaultSmallHeapBins - startingBinNum - 1;
  1554.         blockToCarve = NULL;
  1555.         
  1556.         while (remainingBins--) {
  1557.         
  1558.             currentBin++;
  1559.         
  1560.             currentBinValue = *currentBin;
  1561.             
  1562.             if (currentBinValue != NULL) {
  1563.                 blockToCarve = currentBinValue;
  1564.                 break;
  1565.             }
  1566.             
  1567.         }
  1568.  
  1569.         //    Try carving up up a block from the overflow bin.
  1570.         
  1571.         if (blockToCarve == NULL)
  1572.             blockToCarve = chunk->overflow;
  1573.         
  1574.     doCarve:
  1575.         
  1576.         while (blockToCarve != NULL) {
  1577.         
  1578.             SInt32    blockToCarveSize = blockToCarve->blockSize;
  1579.         
  1580.             //    If the owerflow block is big enough to house the
  1581.             //    allocation, then use it.
  1582.         
  1583.             if (blockToCarveSize >= blockSize) {
  1584.             
  1585.                 SInt32                leftovers;
  1586.             
  1587.                 //    Remove the block from the free list... we will
  1588.                 //    be using it for the allocation...
  1589.                 
  1590.                 RemoveSmallHeapBlockFromFreeList(chunk, blockToCarve);
  1591.  
  1592.                 //    If taking our current allocation out of
  1593.                 //    the overflow block would still leave enough
  1594.                 //    room for another allocation out of the 
  1595.                 //    block, then split the block up.
  1596.                 
  1597.                 leftovers = blockToCarveSize - sizeof(SmallHeapBlock) - MEMORY_BLOCK_TAILER_SIZE - blockSize;
  1598.                 
  1599.                 if (leftovers >= kDefaultSmallHeadMinSize) {
  1600.                 
  1601.                     SmallHeapBlock        *leftoverBlock;
  1602.                     SmallHeapBlock        *nextBlock;
  1603.                 
  1604.                     nextBlock = NextSmallHeapBlock(blockToCarve);
  1605.                     
  1606.                     //    Create a new block out of the leftovers
  1607.                     
  1608.                     leftoverBlock = (SmallHeapBlock *)((char *)blockToCarve + 
  1609.                         sizeof(SmallHeapBlock) + blockSize + MEMORY_BLOCK_TAILER_SIZE); 
  1610.                 
  1611.                     //    Add the block to linked list of blocks in this raw
  1612.                     //    allocation chunk.
  1613.                 
  1614.                     nextBlock->prevBlock = leftoverBlock;
  1615.                     blockToCarve->blockSize = blockSize | kBlockInUseFlag;        
  1616.                         
  1617.                     leftoverBlock->prevBlock = blockToCarve;
  1618.                     leftoverBlock->blockSize = leftovers;
  1619.                     
  1620.                     //    And add the block to a free list, which will either be
  1621.                     //    one of the sized bins or the overflow list, depending
  1622.                     //    on its size.
  1623.                 
  1624.                     AddSmallHeapBlockToFreeList(chunk, leftoverBlock);
  1625.                             
  1626.                 }
  1627.             
  1628.                 blockToCarve->info.inUseInfo.freeProc.blockFreeRoutine = &chunk->header.freeDescriptor;
  1629.  
  1630.     #if STATS_MAC_MEMORY
  1631.                 gTotalSmallHeapBlocksUsed++;
  1632.                 gTotalSmallHeapUsed += TotalSmallHeapBlockUsage(blockToCarve);
  1633.     #endif
  1634. #if DEBUG_MAC_ALLOCATORS && DEBUG_MAC_MEMORY
  1635.                 EnableAllocationSet ( gSmallHeapAllocatorSet );
  1636.                 TrackItem ( blockToCarve, blockSize, 0, kPointerBlock, stackCrawl );
  1637.                 DisableAllocationSet ( gSmallHeapAllocatorSet );
  1638. #endif
  1639.                 return SmallHeapBlockToMemoryPtr(blockToCarve);
  1640.                             
  1641.             } 
  1642.         
  1643.             blockToCarve = blockToCarve->info.freeInfo.nextFree;
  1644.         }
  1645.     
  1646.     chunk = (SmallHeapChunk *) chunk->header.next;
  1647.     }
  1648.         
  1649.     return NULL;
  1650. }
  1651.  
  1652. void SmallHeapFree(void *address, void *refcon)
  1653. {
  1654.     SmallHeapChunk            *chunk = (SmallHeapChunk *)refcon;
  1655.     SmallHeapBlock            *deadBlock,
  1656.                             *prevBlock,
  1657.                             *nextBlock;
  1658.                 
  1659.     deadBlock = MemoryPtrToSmallHeapBlock(address);
  1660.  
  1661. #if DEBUG_MAC_ALLOCATORS && DEBUG_MAC_MEMORY
  1662.     EnableAllocationSet ( gSmallHeapAllocatorSet );
  1663.     ReleaseItem ( deadBlock );
  1664.     DisableAllocationSet ( gSmallHeapAllocatorSet );
  1665. #endif
  1666.  
  1667. #if STATS_MAC_MEMORY
  1668.     gTotalSmallHeapBlocksUsed--;
  1669.     gTotalSmallHeapUsed -= TotalSmallHeapBlockUsage(deadBlock);
  1670. #endif
  1671.  
  1672.     //    If the block after us is free, then coalesce with it.
  1673.     
  1674.     nextBlock = NextSmallHeapBlock(deadBlock);
  1675.     prevBlock = PrevSmallHeapBlock(deadBlock);
  1676.     
  1677.     if (SmallHeapBlockNotInUse(nextBlock)) {    
  1678.         RemoveSmallHeapBlockFromFreeList(chunk, nextBlock);
  1679.         deadBlock->blockSize += TotalSmallHeapBlockUsage(nextBlock);
  1680.         nextBlock = NextSmallHeapBlock(nextBlock);
  1681.     }
  1682.     
  1683.     //    If the block before us is free, then coalesce with it.
  1684.     
  1685.     if (SmallHeapBlockNotInUse(prevBlock)) {
  1686.         RemoveSmallHeapBlockFromFreeList(chunk, prevBlock);
  1687.         prevBlock->blockSize = ((Ptr)nextBlock - (Ptr)prevBlock) - sizeof(SmallHeapBlock) - MEMORY_BLOCK_TAILER_SIZE;
  1688.         AddSmallHeapBlockToFreeList(chunk, prevBlock);
  1689.         deadBlock = prevBlock;
  1690.     }
  1691.     
  1692.     else {    
  1693.         AddSmallHeapBlockToFreeList(chunk, deadBlock);
  1694.     }
  1695.     
  1696.     nextBlock->prevBlock = deadBlock;
  1697.  
  1698. }
  1699.  
  1700.  
  1701. SubHeapAllocationChunk * SmallHeapAllocChunk ( size_t blockSize, void * refcon )
  1702. {
  1703. #pragma unused(blockSize)
  1704.     SmallHeapRoot *            root = refcon;
  1705.     SmallHeapChunk *        chunk;
  1706.     Boolean                    useTemp;
  1707.     Size                    heapSize;
  1708.     SmallHeapBlock *        newFreeOverflowBlock;
  1709.     SmallHeapBlock *        newRawBlockHeader;
  1710.     SmallHeapBlock *        newRawBlockTrailer;
  1711.     UInt32                    count;
  1712. #if DEBUG_ALLOCATION_CHUNKS && DEBUG_MAC_MEMORY
  1713.     void *                    stackCrawl[ kStackDepth ];
  1714.     
  1715.     GetCurrentStackTrace(stackCrawl);
  1716. #endif
  1717.     
  1718.     // if we have a main chunk allocated already, use temp mem
  1719.     useTemp = root->header.firstChunk != NULL;
  1720.     
  1721.     // we allocate a bigger main chunk the first time
  1722.     if ( useTemp )
  1723.         {
  1724.         heapSize = root->tempChunkHeapSize;
  1725.         }
  1726.     else
  1727.         {
  1728.         heapSize = root->baseChunkHeapSize;
  1729.         }
  1730.     
  1731.     chunk = (SmallHeapChunk *) AllocateSubHeap ( &root->header, heapSize + sizeof(SmallHeapChunk), useTemp );
  1732.     if ( chunk != NULL )
  1733.         {
  1734.         // init the overflow and bin ptrs
  1735.         chunk->overflow = NULL;
  1736.         for ( count = 0; count < kDefaultSmallHeapBins; ++count )
  1737.             {
  1738.             chunk->bins[ count ] = NULL;
  1739.             }
  1740.         
  1741.         // mark how much we can actually store in the heap
  1742.         chunk->header.heapSize = heapSize - 3 * sizeof(SmallHeapBlock);
  1743.         
  1744.         newRawBlockHeader = chunk->memory;
  1745.  
  1746.         chunk->header.freeDescriptor.freeRoutine = SmallHeapFree;
  1747.         chunk->header.freeDescriptor.sizeRoutine = SmallBlockSize;
  1748.         chunk->header.freeDescriptor.refcon = chunk;
  1749.  
  1750. #if DEBUG_ALLOCATION_CHUNKS && DEBUG_MAC_MEMORY
  1751.         EnableAllocationSet ( gSmallHeapAllocatorSet );
  1752.         TrackItem ( newRawBlockHeader, heapSize, 0, kPointerBlock, stackCrawl );
  1753.         DisableAllocationSet ( gSmallHeapAllocatorSet );
  1754. #endif
  1755.  
  1756.         //    The first few bytes of the block are a dummy header
  1757.         //    which is a block of size zero that is always alloacted.  
  1758.         //    This allows our coalesce code to work without modification
  1759.         //    on the edge case of coalescing the first real block.
  1760.  
  1761.         newRawBlockHeader->prevBlock = NULL;
  1762.         newRawBlockHeader->blockSize = kBlockInUseFlag;
  1763.         newRawBlockHeader->info.inUseInfo.freeProc.blockFreeRoutine = NULL;
  1764.         
  1765.         newFreeOverflowBlock = NextSmallHeapBlock(newRawBlockHeader);
  1766.         
  1767.         newFreeOverflowBlock->prevBlock = newRawBlockHeader;
  1768.         newFreeOverflowBlock->blockSize = heapSize - 3 * sizeof(SmallHeapBlock) - 3 * MEMORY_BLOCK_TAILER_SIZE;
  1769.  
  1770.         //    The same is true for the last few bytes in the block 
  1771.         //    as well.
  1772.         
  1773.         newRawBlockTrailer = (SmallHeapBlock *)(((Ptr)newRawBlockHeader) + heapSize - sizeof(SmallHeapBlock) - MEMORY_BLOCK_TAILER_SIZE);
  1774.         newRawBlockTrailer->prevBlock = newFreeOverflowBlock;
  1775.         newRawBlockTrailer->blockSize = kBlockInUseFlag | 0xFFFFFFFF;
  1776.         newRawBlockTrailer->info.inUseInfo.freeProc.blockFreeRoutine = NULL;
  1777.         
  1778.         AddSmallHeapBlockToFreeList(chunk, newFreeOverflowBlock);
  1779.         }
  1780.     
  1781.     return &chunk->header;
  1782. }
  1783.  
  1784. size_t SmallBlockSize (void *block, void *refcon)
  1785. {
  1786. #pragma unused(refcon)
  1787.     SmallHeapBlock            *blockHeader;
  1788.                 
  1789.     blockHeader = MemoryPtrToSmallHeapBlock(block);
  1790.     
  1791.     return ( blockHeader->blockSize & ~kBlockInUseFlag );
  1792. }
  1793.  
  1794. void SmallBlockHeapFree(size_t blockSize, FreeMemoryStats * stats, void * refcon)
  1795. {
  1796. #pragma unused(blockSize)
  1797.     SmallHeapRoot *            root = refcon;
  1798.     SmallHeapChunk *        chunk;
  1799.     uint32                    freeBytes;
  1800.     uint32                    totalBytes;
  1801.     uint32                    maxBlock;
  1802.     uint32                    bin;
  1803.     uint32                    curBlockSize;
  1804.     SmallHeapBlock *        freeList;
  1805.         
  1806.     freeBytes = 0;
  1807.     maxBlock = 0;
  1808.     totalBytes = 0;
  1809.     
  1810.     chunk = (SmallHeapChunk *) root->header.firstChunk;
  1811.     while ( chunk != NULL )
  1812.         {
  1813.         /* count up the free blocks in all of the bins */
  1814.         for ( bin = 0; bin < kDefaultSmallHeapBins; ++bin )
  1815.             {
  1816.             for ( freeList = chunk->bins[ bin ]; freeList != NULL; freeList = freeList->info.freeInfo.nextFree )
  1817.                 {
  1818.                 curBlockSize = freeList->blockSize & ~kBlockInUseFlag;
  1819.                 
  1820.                 freeBytes += curBlockSize;
  1821.                 if ( maxBlock < curBlockSize )
  1822.                     {
  1823.                     maxBlock = curBlockSize;
  1824.                     }
  1825.                 }
  1826.             }
  1827.         
  1828.         /* add in the overflow block */
  1829.         freeBytes += chunk->overflow->blockSize & ~kBlockInUseFlag;
  1830.         
  1831.         totalBytes += chunk->header.heapSize;
  1832.         
  1833.         chunk = (SmallHeapChunk *) chunk->header.next;
  1834.         }
  1835.         
  1836.     stats->maxBlockSize = maxBlock;
  1837.     stats->totalHeapSize = totalBytes;
  1838.     stats->totalFreeBytes = freeBytes;
  1839. }
  1840.  
  1841. //##############################################################################
  1842. //##############################################################################
  1843. #pragma mark -
  1844. #pragma mark TRACKING MEMORY MANAGER MEMORY
  1845.  
  1846. #if DEBUG_MAC_MEMORY
  1847. #if GENERATINGPOWERPC
  1848.  
  1849. enum {
  1850.     uppNewHandleProcInfo = kRegisterBased
  1851.          | RESULT_SIZE(SIZE_CODE(sizeof(Handle)))
  1852.          | REGISTER_RESULT_LOCATION(kRegisterA0)
  1853.          | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(UInt16)))
  1854.          | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(Size))),
  1855.     uppNewPtrProcInfo = kRegisterBased
  1856.          | RESULT_SIZE(SIZE_CODE(sizeof(Handle)))
  1857.          | REGISTER_RESULT_LOCATION(kRegisterA0)
  1858.          | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(UInt16)))
  1859.          | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(Size))),
  1860.     uppDisposeHandleProcInfo = kRegisterBased
  1861.          | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(UInt16)))
  1862.          | REGISTER_ROUTINE_PARAMETER(2, kRegisterA0, SIZE_CODE(sizeof(Handle))),
  1863.     uppDisposePtrProcInfo = kRegisterBased
  1864.          | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(UInt16)))
  1865.          | REGISTER_ROUTINE_PARAMETER(2, kRegisterA0, SIZE_CODE(sizeof(Ptr)))
  1866. };
  1867.  
  1868. extern pascal Handle NewHandlePatch(UInt16 trapWord, Size byteCount);
  1869. extern pascal Ptr NewPtrPatch(UInt16 trapWord, Size byteCount);
  1870. extern pascal void DisposeHandlePatch(UInt16 trapWord, Handle deadHandle);
  1871. extern pascal void DisposePtrPatch(UInt16 trapWord, Ptr deadPtr);
  1872.  
  1873. RoutineDescriptor    gNewHandlePatchRD = BUILD_ROUTINE_DESCRIPTOR(uppNewHandleProcInfo, &NewHandlePatch);
  1874. RoutineDescriptor    gNewPtrPatchRD = BUILD_ROUTINE_DESCRIPTOR(uppNewPtrProcInfo, &NewPtrPatch);
  1875. RoutineDescriptor    gDisposeHandlePatchRD = BUILD_ROUTINE_DESCRIPTOR(uppDisposeHandleProcInfo, &DisposeHandlePatch);
  1876. RoutineDescriptor    gDisposePtrPatchRD = BUILD_ROUTINE_DESCRIPTOR(uppDisposePtrProcInfo, &DisposePtrPatch);
  1877.  
  1878. UniversalProcPtr    gNewHandlePatchCallThru = NULL;
  1879. UniversalProcPtr     gNewPtrPatchCallThru = NULL;
  1880. UniversalProcPtr    gDisposeHandlePatchCallThru = NULL;
  1881. UniversalProcPtr     gDisposePtrPatchCallThru = NULL;
  1882.  
  1883.  
  1884.  
  1885. extern pascal Handle NewHandlePatch(UInt16 trapWord, Size byteCount)
  1886. {
  1887.     void            *stackCrawl[kStackDepth];
  1888.     Handle            resultHandle;
  1889.     
  1890.     GetCurrentStackTrace(stackCrawl);
  1891.  
  1892.     resultHandle = (Handle)CallOSTrapUniversalProc(gNewHandlePatchCallThru, uppNewHandleProcInfo, trapWord, byteCount);
  1893.  
  1894.     if (resultHandle && DEBUG_TRACK_MACOS_MEMS) {
  1895.         TrackItem ( resultHandle, byteCount, 0, kHandleBlock, stackCrawl );
  1896.         gOutstandingHandles++;
  1897.     }
  1898.     
  1899.     return resultHandle;
  1900.     
  1901. }
  1902.  
  1903. extern pascal Ptr NewPtrPatch(UInt16 trapWord, Size byteCount)
  1904. {    
  1905.     void            *stackCrawl[kStackDepth];
  1906.     Ptr                resultPtr;
  1907.  
  1908.     GetCurrentStackTrace(stackCrawl);
  1909.     
  1910.     resultPtr = (Ptr)CallOSTrapUniversalProc(gNewPtrPatchCallThru, uppNewPtrProcInfo, trapWord, byteCount);
  1911.  
  1912.     if (resultPtr && DEBUG_TRACK_MACOS_MEMS) {
  1913.         TrackItem ( resultPtr, byteCount, 0, kPointerBlock, stackCrawl );
  1914.         gOutstandingPointers++;
  1915.     }
  1916.     
  1917.     return resultPtr;
  1918.     
  1919. }
  1920.  
  1921. pascal void DisposeHandlePatch(UInt16 trapWord, Handle deadHandle)
  1922. {
  1923. #if DEBUG_TRACK_MACOS_MEMS
  1924.     ReleaseItem(deadHandle);
  1925. #endif
  1926.     gOutstandingHandles--;
  1927.  
  1928.     CallOSTrapUniversalProc(gDisposeHandlePatchCallThru, uppDisposeHandleProcInfo, trapWord, deadHandle);
  1929. }
  1930.  
  1931. pascal void DisposePtrPatch(UInt16 trapWord, Ptr deadPtr)
  1932. {
  1933. #if DEBUG_TRACK_MACOS_MEMS
  1934.     ReleaseItem(deadPtr);
  1935. #endif
  1936.     gOutstandingPointers--;
  1937.  
  1938.     CallOSTrapUniversalProc(gDisposePtrPatchCallThru, uppDisposePtrProcInfo, trapWord, deadPtr);
  1939. }
  1940.  
  1941.  
  1942. void InstallMemoryManagerPatches(void)
  1943. {
  1944.     OSErr                err;
  1945.     
  1946.     err = Gestalt ( gestaltLogicalRAMSize, (long *) &gMemoryTop );
  1947.     if ( err != noErr )
  1948.         {
  1949.         DebugStr ( "\pThis machine has no logical ram?" );
  1950.         ExitToShell();
  1951.         }
  1952.  
  1953.     gNewHandlePatchCallThru = GetOSTrapAddress(0x0122);
  1954.     SetOSTrapAddress(&gNewHandlePatchRD, 0x0122);
  1955.     
  1956.     gNewPtrPatchCallThru = GetOSTrapAddress(0x011E);
  1957.     SetOSTrapAddress(&gNewPtrPatchRD, 0x011E);
  1958.  
  1959.     gDisposeHandlePatchCallThru = GetOSTrapAddress(0x023);
  1960.     SetOSTrapAddress(&gDisposeHandlePatchRD, 0x023);
  1961.  
  1962.     gDisposePtrPatchCallThru = GetOSTrapAddress(0x001F);
  1963.     SetOSTrapAddress(&gDisposePtrPatchRD, 0x001F);
  1964.  
  1965.     /* init the tracker itself and then add our block type decoders */
  1966.     InitializeMemoryTracker();
  1967.     SetTrackerDataDecoder ( kMallocBlock, PrintStackCrawl );
  1968.     SetTrackerDataDecoder ( kHandleBlock, PrintStackCrawl );
  1969.     SetTrackerDataDecoder ( kPointerBlock, PrintStackCrawl );
  1970.     
  1971.     gExitToShellPatchCallThru = GetToolboxTrapAddress(0x01F4);
  1972.     SetToolboxTrapAddress((UniversalProcPtr)&gExitToShellPatchRD, 0x01F4);
  1973. }
  1974.  
  1975. #else
  1976.  
  1977. void InstallMemoryManagerPatches(void)
  1978. {
  1979.     
  1980. }
  1981.  
  1982. #endif
  1983. #endif
  1984.  
  1985.  
  1986. #if DEBUG_MAC_MEMORY && GENERATINGPOWERPC
  1987.  
  1988. /*
  1989.  * Stuff for tracking memory leaks
  1990.  */
  1991. pascal void TrackerExitToShellPatch(void)
  1992. {
  1993. static Boolean gBeenHere = false;
  1994.  
  1995.     /* if we haven't been here, then dump our memory state, otherwise don't */
  1996.     /* this way we don't hose ourselves if we crash in here */
  1997.     if ( !gBeenHere )
  1998.         {
  1999.         gBeenHere = true;
  2000.         DumpMemoryTrackerState();
  2001.         
  2002. #if STATS_MAC_MEMORY
  2003.         DumpMemoryStats();
  2004. #endif
  2005.         }
  2006.  
  2007.     ExitMemoryTracker();
  2008.  
  2009. #if GENERATINGCFM
  2010.     CallUniversalProc(gExitToShellPatchCallThru, uppExitToShellProcInfo);
  2011. #else 
  2012.     {
  2013.         ExitToShellProc    *exitProc = (ExitToShellProc *)&gExitToShellPatchCallThru;
  2014.         (*exitProc)();
  2015.     }
  2016. #endif
  2017. }
  2018.  
  2019.  
  2020. static void PrintStackCrawl ( void ** stackCrawl, char * name )
  2021. {
  2022.     unsigned long        currentStackLevel;
  2023.     
  2024.     *name = 0;
  2025.     
  2026.     for (currentStackLevel = 0; currentStackLevel < kStackDepth; currentStackLevel++)
  2027.         {
  2028.         CatenateRoutineNameFromPC ( name, stackCrawl[ currentStackLevel ] );
  2029.         
  2030.         if (currentStackLevel < kStackDepth - 1)
  2031.             strcat( name, "," );
  2032.         }
  2033. }
  2034.  
  2035. static void CatenateRoutineNameFromPC( char * string, void *currentPC )
  2036. {
  2037.     UInt32        instructionsToLook = kMaxInstructionScanDistance;
  2038.     UInt32        *currentPCAsLong = (UInt32 *)currentPC;
  2039.     UInt32        offset = 0;
  2040.     char        labelString[ 512 ];
  2041.     char        lameString[ 512 ];
  2042.     
  2043.     if (currentPC == NULL)
  2044.         return;
  2045.  
  2046.     /* make sure we're not out in the weeds */
  2047.     if ( (unsigned long) currentPC > (unsigned long) gMemoryTop )
  2048.         return;
  2049.         
  2050.     if ( (unsigned long) currentPC & 0x3 )
  2051.         return;
  2052.     
  2053.     *labelString = 0;
  2054.     *lameString = 0;
  2055.     
  2056.     while (instructionsToLook--) {
  2057.     
  2058.         if (*currentPCAsLong == 0x4E800020) {
  2059.             char    stringLength = *((char *)currentPCAsLong + 21);
  2060.             memset( labelString, 0, 512 );
  2061.             BlockMoveData( ((char *)currentPCAsLong + 22), labelString, stringLength );
  2062.             
  2063.             // if there was no routine name, then just put down the address.
  2064.             if ( *labelString == 0 )
  2065.                 {
  2066.                 PrintHexNumber( lameString, (unsigned long) currentPC );
  2067.                 goto bail;
  2068.                 }
  2069.             else
  2070.                 {
  2071.                 strcat ( lameString, labelString );
  2072.                 strcat ( lameString, "+" );
  2073.                 }
  2074.             break;
  2075.         }
  2076.     
  2077.         currentPCAsLong++;
  2078.     }
  2079.     
  2080.     instructionsToLook = kMaxInstructionScanDistance;
  2081.     currentPCAsLong = (UInt32 *)currentPC;
  2082.     
  2083.     *labelString = 0;
  2084.         
  2085.     while (instructionsToLook--) {
  2086.         if (*currentPCAsLong == 0x7C0802A6) {
  2087.  
  2088.             PrintHexNumber( labelString, offset - 4 );
  2089.             strcat ( lameString, labelString );
  2090.             break;
  2091.         }
  2092.         currentPCAsLong--;
  2093.         offset += 4;
  2094.     }
  2095.  
  2096. bail:    
  2097.     /* make sure we don't end up being too big */
  2098.     lameString[ kNameMaxLength ] = 0;
  2099.     strcat ( string, lameString );
  2100. }
  2101.  
  2102. #endif
  2103.  
  2104. #if GENERATINGPOWERPC
  2105.  
  2106. asm void *GetCurrentStackPointer()
  2107. {
  2108.     mr        r3, sp
  2109.     lwz        r3, 0(r3)
  2110.     blr
  2111. }
  2112.  
  2113.  
  2114. void GetCurrentStackTrace(void **stackCrawl)
  2115. {
  2116. #if DEBUG_MAC_MEMORY
  2117.     void *        currentSP;
  2118.     void *        interfaceLibSP;
  2119.     void *        callerFirstStackFrame;
  2120.     void *        callerSP;
  2121.     UInt32        stackFrameLevel;
  2122.     UInt8        isPowerPC = true;
  2123.     void *        nextFrame;
  2124.     long        nativeFrames;
  2125.     PRThread *    curThread;
  2126.     void *        stackMin;
  2127.     void *        stackMax;
  2128.         
  2129.     memset(stackCrawl, 0, sizeof(void *) * kStackDepth);
  2130.     
  2131. #if !GENERATINGPOWERPC
  2132.     return;
  2133. #endif
  2134.  
  2135.     curThread = PR_CurrentThread();
  2136.     if ( curThread != NULL && curThread->stack->stackBottom != 0 )
  2137.         {
  2138.         stackMin = curThread->stack->stackBottom;
  2139.         stackMax = curThread->stack->stackTop;
  2140.         }
  2141.     else
  2142.         {
  2143.         stackMin = gOurApplicationHeapBase;
  2144.         stackMax = gOurApplicationHeapMax;
  2145.         }
  2146.  
  2147.     //    If the current SP is not in our heap, then bail (OT ).
  2148.     
  2149. #if GENERATINGPOWERPC
  2150.     currentSP = GetCurrentStackPointer();
  2151. #endif
  2152.  
  2153.     if ((currentSP > gOurApplicationHeapMax) || (currentSP < gOurApplicationHeapBase))
  2154.         return;
  2155.         
  2156.     interfaceLibSP = *((void **)currentSP);
  2157.     
  2158.     callerFirstStackFrame = interfaceLibSP;
  2159.     nextFrame = callerFirstStackFrame;
  2160.         
  2161.     //    What we really want to do here is walk up the stack until we get to a native frame that is in
  2162.     //    one of our Shared libraries... Since they can live in temp mem, this gets whacky.
  2163.     
  2164.     //    So, for now, I just walk up until I hit two native frames in a row...
  2165.     nativeFrames = 0;
  2166.     
  2167.     while (1) {
  2168.         // if this frame is outside of our thread's stack, then bail
  2169.         if ( ( nextFrame > stackMax ) || ( nextFrame < stackMin ) )
  2170.             {
  2171.             return;
  2172.             }
  2173.                 
  2174.         //    Walk the stack differently whether we are at a
  2175.         //    PowerPC or 68K frame...
  2176.  
  2177.         if (isPowerPC) {
  2178.  
  2179. #if 0
  2180.             void    *framePC;
  2181.  
  2182.             //    If we are PowerPC, check to see if the PC
  2183.             //    corresponding to the current frame is in the
  2184.             //    the app's code space.  If so, then we are
  2185.             //    done and we break out.
  2186.             
  2187.             framePC = *((void **)callerFirstStackFrame + 2);
  2188.             if ((framePC < gOurApplicationHeapMax) && (framePC > gOurApplicationHeapBase))
  2189.                 break;
  2190. #endif
  2191.                 
  2192.             //    Otherwise, check the pointer to the next
  2193.             //    stack frame.  If its low bit is set, then
  2194.             //    it is a mixed-mode switch frame, and 
  2195.             //    we need to switch to 68K frames.
  2196.  
  2197.             nextFrame = *((void **)callerFirstStackFrame);
  2198.             
  2199.             isPowerPC = ((UInt32)nextFrame & 0x00000001) == 0;            
  2200.             callerFirstStackFrame = (void *)((UInt32)nextFrame & 0xFFFFFFFE);
  2201.             if ( isPowerPC != false )
  2202.                 {
  2203.                 if ( ++nativeFrames >= 1 )
  2204.                     {
  2205.                     break;
  2206.                     }
  2207.                 }
  2208.         }
  2209.     
  2210.         else {
  2211.             
  2212.             nativeFrames = 0;
  2213.             
  2214.             //    68K case:  If the location immediately above the stack
  2215.             //    frame pointer is -1, then we are at a switch frame,
  2216.             //    move back to PowerPC.
  2217.  
  2218.             if (*((UInt32 *)callerFirstStackFrame - 1) == 0xFFFFFFFF)
  2219.                 isPowerPC = true;
  2220.             callerFirstStackFrame = *((void **)callerFirstStackFrame);
  2221.             nextFrame = callerFirstStackFrame;
  2222.         }
  2223.     
  2224.     }
  2225.     
  2226.     callerSP = callerFirstStackFrame;
  2227.     
  2228.     for (stackFrameLevel = 0; stackFrameLevel < kStackDepth; stackFrameLevel++) {
  2229.     
  2230.         if ( ( callerSP > stackMax ) || ( callerSP < stackMin ) )
  2231.             {
  2232.             return;
  2233.             }
  2234.             
  2235.         stackCrawl[stackFrameLevel] = *(((void **)callerSP) + 2);
  2236.         
  2237.         callerSP = *((void **)callerSP);
  2238.     }
  2239. #else
  2240. #pragma unused(stackCrawl)
  2241. #endif
  2242. }
  2243.  
  2244.  
  2245. void GetCurrentNativeStackTrace ( void ** stackCrawl )
  2246. {
  2247. #if DEBUG_MAC_MEMORY
  2248.     void *        currentSP;
  2249.     UInt32        stackFrameLevel;
  2250.     PRThread *    curThread;
  2251.     void *        stackMin;
  2252.     void *        stackMax;
  2253.     
  2254.     memset(stackCrawl, 0, sizeof(void *) * kStackDepth);
  2255.     
  2256. #if GENERATINGPOWERPC
  2257.     currentSP = GetCurrentStackPointer();
  2258. #else
  2259.     return;
  2260. #endif
  2261.  
  2262.     curThread = PR_CurrentThread();
  2263.     if ( curThread != NULL && curThread->stack->stackBottom != 0 )
  2264.         {
  2265.         stackMin = curThread->stack->stackBottom;
  2266.         stackMax = curThread->stack->stackTop;
  2267.         }
  2268.     else
  2269.         {
  2270.         stackMin = gOurApplicationHeapBase;
  2271.         stackMax = gOurApplicationHeapMax;
  2272.         }
  2273.         
  2274.     for (stackFrameLevel = 0; stackFrameLevel < kStackDepth; stackFrameLevel++) {
  2275.         if ( ( currentSP > stackMax ) || ( currentSP < stackMin ) )
  2276.             {
  2277.             return;
  2278.             }
  2279.             
  2280.         stackCrawl[stackFrameLevel] = *((void **)((char *)currentSP + 8));
  2281.         currentSP = *((void **)currentSP);
  2282.     }
  2283. #else
  2284. #pragma unused(stackCrawl)
  2285. #endif
  2286. }
  2287.  
  2288. #endif
  2289.  
  2290.