home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 1999 February / DPPCPRO0299.ISO / February / Delphi / Install / DATA.Z / GETMEM.INC < prev    next >
Encoding:
Text File  |  1996-06-11  |  33.5 KB  |  1,385 lines

  1. // Three layers:
  2. // - Address space administration
  3. // - Committed space administration
  4. // - Suballocator
  5. //
  6. // Helper module: administrating block descriptors
  7. //
  8.  
  9.  
  10. //
  11. // Operating system interface
  12. //
  13. const
  14.   LMEM_FIXED = 0;
  15.   LMEM_ZEROINIT = $40;
  16.  
  17.   MEM_COMMIT   = $1000;
  18.   MEM_RESERVE  = $2000;
  19.   MEM_DECOMMIT = $4000;
  20.   MEM_RELEASE  = $8000;
  21.  
  22.   PAGE_NOACCESS  = 1;
  23.   PAGE_READWRITE = 4;
  24.  
  25. type
  26.   DWORD = Integer;
  27.   BOOL  = LongBool;
  28.  
  29.   TRTLCriticalSection = record
  30.     DebugInfo: Pointer;
  31.     LockCount: Longint;
  32.     RecursionCount: Longint;
  33.     OwningThread: Integer;
  34.     LockSemaphore: Integer;
  35.     Reserved: DWORD;
  36.   end;
  37.  
  38. function LocalAlloc(flags, size: Integer): Pointer; stdcall;
  39.   external kernel name 'LocalAlloc';
  40. function LocalFree(addr: Pointer): Pointer; stdcall;
  41.   external kernel name 'LocalFree';
  42.  
  43. function VirtualAlloc(lpAddress: Pointer;
  44.   dwSize, flAllocationType, flProtect: DWORD): Pointer; stdcall;
  45.   external kernel name 'VirtualAlloc';
  46. function VirtualFree(lpAddress: Pointer; dwSize, dwFreeType: DWORD): BOOL; stdcall;
  47.   external kernel name 'VirtualFree';
  48.  
  49. procedure InitializeCriticalSection(var lpCriticalSection: TRTLCriticalSection); stdcall;
  50.   external kernel name 'InitializeCriticalSection';
  51. procedure EnterCriticalSection(var lpCriticalSection: TRTLCriticalSection); stdcall;
  52.   external kernel name 'EnterCriticalSection';
  53. procedure LeaveCriticalSection(var lpCriticalSection: TRTLCriticalSection); stdcall;
  54.   external kernel name 'LeaveCriticalSection';
  55. procedure DeleteCriticalSection(var lpCriticalSection: TRTLCriticalSection); stdcall;
  56.   external kernel name 'DeleteCriticalSection';
  57.  
  58. // Common Data structure:
  59.  
  60. type
  61.   TBlock = record
  62.     addr: PChar;
  63.     size: Integer;
  64.   end;
  65.  
  66. // Heap error codes
  67.  
  68. const
  69.   cHeapOk        = 0;    // everything's fine
  70.   cReleaseErr        = 1;    // operating system returned an error when we released
  71.   cDecommitErr      = 2;    // operating system returned an error when we decommited
  72.   cBadCommittedList = 3;    // list of committed blocks looks bad
  73.   cBadFiller1       = 4;    // filler block is bad
  74.   cBadFiller2       = 5;    // filler block is bad
  75.   cBadFiller3       = 6;    // filler block is bad
  76.   cBadCurAlloc      = 7;    // current allocation zone is bad
  77.   cCantInit         = 8;    // couldn't initialize
  78.   cBadUsedBlock     = 9;    // used block looks bad
  79.   cBadPrevBlock     = 10;    // prev block before a used block is bad
  80.   cBadNextBlock     = 11;    // next block after a used block is bad
  81.   cBadFreeList      = 12;    // free list is bad
  82.   cBadFreeBlock     = 13;    // free block is bad
  83.   cBadBalance       = 14;    // free list doesn't correspond to blocks marked free
  84.  
  85. var
  86.   initialized   : Boolean;
  87.   heapErrorCode : Integer;
  88.   heapLock      : TRTLCriticalSection;
  89.  
  90. //
  91. // Helper module: administrating block descriptors.
  92. //
  93. type
  94.   PBlockDesc = ^TBlockDesc;
  95.   TBlockDesc = record
  96.     next: PBlockDesc;
  97.     prev: PBlockDesc;
  98.     addr: PChar;
  99.     size: Integer;
  100.   end;
  101.  
  102. type
  103.   PBlockDescBlock = ^TBlockDescBlock;
  104.   TBlockDescBlock = record
  105.     next: PBlockDescBlock;
  106.     data: array [0..99] of TBlockDesc;
  107.   end;
  108.  
  109. var
  110.   blockDescBlockList: PBlockDescBlock;
  111.   blockDescFreeList : PBlockDesc;
  112.  
  113.  
  114. function GetBlockDesc: PBlockDesc;
  115. // Get a block descriptor.
  116. // Will return nil for failure.
  117. var
  118.   bd:  PBlockDesc;
  119.   bdb: PBlockDescBlock;
  120.   i:   Integer;
  121. begin
  122.   if blockDescFreeList = nil then begin
  123.     bdb := LocalAlloc(LMEM_FIXED, sizeof(bdb^));
  124.     if bdb = nil then begin
  125.       result := nil;
  126.       exit;
  127.     end;
  128.     bdb.next := blockDescBlockList;
  129.     blockDescBlockList := bdb;
  130.     for i := low(bdb.data) to high(bdb.data) do begin
  131.       bd := @bdb.data[i];
  132.       bd.next := blockDescFreeList;
  133.       blockDescFreeList := bd;
  134.     end;
  135.   end;
  136.   bd := blockDescFreeList;
  137.   blockDescFreeList := bd.next;
  138.   result := bd;
  139. end;
  140.  
  141.  
  142. procedure FreeBlockDesc(blockDesc: PBlockDesc);
  143. // Free a block descriptor.
  144. begin
  145.   blockDesc.next := blockDescFreeList;
  146.   blockDescFreeList := blockDesc;
  147. end;
  148.  
  149.  
  150. procedure MakeEmpty(bd: PBlockDesc);
  151. begin
  152.   bd.next := bd;
  153.   bd.prev := bd;
  154. end;
  155.  
  156.  
  157. function AddBlockAfter(prev: PBlockDesc; const b: TBlock): Boolean;
  158. var
  159.   next, bd: PBlockDesc;
  160. begin
  161.   bd := GetBlockDesc;
  162.   if bd = nil then
  163.     result := False
  164.   else begin
  165.     bd.addr := b.addr;
  166.     bd.size := b.size;
  167.  
  168.     next := prev.next;
  169.     bd.next := next;
  170.     bd.prev := prev;
  171.     next.prev := bd;
  172.     prev.next := bd;
  173.  
  174.     result := True;
  175.   end;
  176. end;
  177.  
  178.  
  179. procedure DeleteBlock(bd: PBlockDesc);
  180. var
  181.   prev, next: PBlockDesc;
  182. begin
  183.   prev := bd.prev;
  184.   next := bd.next;
  185.   prev.next := next;
  186.   next.prev := prev;
  187. end;
  188.  
  189.  
  190. function MergeBlockAfter(prev: PBlockDesc; const b: TBlock) : TBlock;
  191. var
  192.   bd: PBlockDesc;
  193. begin
  194.   bd := prev.next;
  195.   result := b;
  196.   repeat
  197.     if bd.addr + bd.size = result.addr then begin
  198.       DeleteBlock(bd);
  199.       result.addr := bd.addr;
  200.       inc(result.size, bd.size);
  201.     end else if result.addr + result.size = bd.addr then begin
  202.       DeleteBlock(bd);
  203.       inc(result.size, bd.size);
  204.     end;
  205.     bd := bd.next;
  206.   until bd = prev;
  207.   if not AddBlockAfter(prev, result) then
  208.     result.addr := nil;
  209. end;
  210.  
  211.  
  212. function RemoveBlock(bd: PBlockDesc; const b: TBlock): Boolean;
  213. var
  214.   n: TBlock;
  215.   start: PBlockDesc;
  216. begin
  217.   start := bd;
  218.   repeat
  219.     if (bd.addr <= b.addr) and (bd.addr + bd.size >= b.addr + b.size) then begin
  220.       if bd.addr = b.addr then begin
  221.     Inc(bd.addr, b.size);
  222.     Dec(bd.size, b.size);
  223.     if bd.size = 0 then
  224.       DeleteBlock(bd);
  225.       end else if bd.addr + bd.size = b.addr + b.size then
  226.     Dec(bd.size, b.size)
  227.       else begin
  228.     n.addr := b.addr + b.size;
  229.     n.size := bd.addr + bd.size - n.addr;
  230.     bd.size := b.addr - bd.addr;
  231.     if not AddBlockAfter(bd, n) then begin
  232.       result := False;
  233.       exit;
  234.     end;
  235.       end;
  236.       result := True;
  237.       exit;
  238.     end;
  239.     bd := bd.next;
  240.   until bd = start;
  241.   result := False;
  242. end;
  243.  
  244.  
  245.  
  246. //
  247. // Address space administration:
  248. //
  249.  
  250. const
  251.   cSpaceAlign = 64*1024;
  252.   cSpaceMin   = 1024*1024;
  253.   cPageAlign  = 4*1024;
  254.  
  255. var
  256.   spaceRoot: TBlockDesc;
  257.  
  258.  
  259. function GetSpace(minSize: Integer): TBlock;
  260. // Get at least minSize bytes address space.
  261. // Success: returns a block, possibly much bigger than requested.
  262. // Will not fail - will raise an exception or terminate program.
  263. begin
  264.   if minSize < cSpaceMin then
  265.     minSize := cSpaceMin
  266.   else
  267.     minSize := (minSize + (cSpaceAlign-1)) and not (cSpaceAlign-1);
  268.  
  269.   result.size := minSize;
  270.   result.addr := VirtualAlloc(nil, minSize, MEM_RESERVE, PAGE_NOACCESS);
  271.   if result.addr = nil then
  272.     exit;
  273.  
  274.   if not AddBlockAfter(@spaceRoot, result) then begin
  275.     VirtualFree(result.addr, 0, MEM_RELEASE);
  276.     result.addr := nil;
  277.     exit;
  278.   end;
  279. end;
  280.  
  281.  
  282. function GetSpaceAt(addr: PChar; minSize: Integer): TBlock;
  283. // Get at least minSize bytes address space at addr.
  284. // Return values as above.
  285. // Failure: returns block with addr = nil.
  286. begin
  287.   result.size := cSpaceMin;
  288.   result.addr := VirtualAlloc(addr, cSpaceMin, MEM_RESERVE, PAGE_READWRITE);
  289.   if result.addr = nil then begin
  290.     minSize := (minSize + (cSpaceAlign-1)) and not (cSpaceAlign-1);
  291.     result.size := minSize;
  292.     result.addr := VirtualAlloc(addr, minSize, MEM_RESERVE, PAGE_READWRITE);
  293.   end;
  294.   if result.addr <> nil then begin
  295.     if not AddBlockAfter(@spaceRoot, result) then begin
  296.       VirtualFree(result.addr, 0, MEM_RELEASE);
  297.       result.addr := nil;
  298.     end;
  299.   end;
  300. end;
  301.  
  302.  
  303. function FreeSpace(addr: Pointer; maxSize: Integer): TBlock;
  304. // Free at most maxSize bytes of address space at addr.
  305. // Returns the block that was actually freed.
  306. var
  307.   bd: PBlockDesc;
  308.   minAddr, maxAddr, startAddr, endAddr: PChar;
  309. begin
  310.   minAddr := PChar($FFFFFFFF);
  311.   maxAddr := nil;
  312.   startAddr := addr;
  313.   endAddr   := startAddr + maxSize;
  314.   bd := spaceRoot.next;
  315.   while bd <> @spaceRoot do begin
  316.     if (bd.addr >= startAddr) and (bd.addr + bd.size <= endAddr) then begin
  317.       if minAddr > bd.addr then
  318.     minAddr := bd.addr;
  319.       if maxAddr < bd.addr + bd.size then
  320.     maxAddr := bd.addr + bd.size;
  321.       if not VirtualFree(bd.addr, 0, MEM_RELEASE) then
  322.     heapErrorCode := cReleaseErr;
  323.       DeleteBlock(bd);
  324.     end;
  325.     bd := bd.next;
  326.   end;
  327.   result.addr := nil;
  328.   if maxAddr <> nil then begin
  329.     result.addr := minAddr;
  330.     result.size := maxAddr - minAddr;
  331.   end;
  332. end;
  333.  
  334.  
  335. function Commit(addr: Pointer; minSize: Integer): TBlock;
  336. // Commits memory.
  337. // Returns the block that was actually committed.
  338. // Will return a block with addr = nil on failure.
  339. var
  340.   bd: PBlockDesc;
  341.   loAddr, hiAddr, startAddr, endAddr: PChar;
  342. begin
  343.   startAddr := PChar(Integer(addr) and not (cPageAlign-1));
  344.   endAddr := PChar(((Integer(addr) + minSize) + (cPageAlign-1)) and not (cPageAlign-1));
  345.   result.addr := startAddr;
  346.   result.size := endAddr - startAddr;
  347.   bd := spaceRoot.next;
  348.   while bd <> @spaceRoot do begin
  349.     // Commit the intersection of the block described by bd and [startAddr..endAddr)
  350.     loAddr := bd.addr;
  351.     hiAddr := loAddr + bd.size;
  352.     if loAddr < startAddr then
  353.       loAddr := startAddr;
  354.     if hiAddr > endAddr then
  355.       hiAddr := endAddr;
  356.     if loAddr < hiAddr then begin
  357.       if VirtualAlloc(loAddr, hiAddr - loAddr, MEM_COMMIT, PAGE_READWRITE) = nil then begin
  358.     result.addr := nil;
  359.     exit;
  360.       end;
  361.     end;
  362.     bd := bd.next;
  363.   end;
  364. end;
  365.  
  366.  
  367. function Decommit(addr: Pointer; maxSize: Integer): TBlock;
  368. // Decommits address space.
  369. // Returns the block that was actually decommitted.
  370. var
  371.   bd: PBlockDesc;
  372.   loAddr, hiAddr, startAddr, endAddr: PChar;
  373. begin
  374.   startAddr := PChar((Integer(addr) + + (cPageAlign-1)) and not (cPageAlign-1));
  375.   endAddr := PChar((Integer(addr) + maxSize) and not (cPageAlign-1));
  376.   result.addr := startAddr;
  377.   result.size := endAddr - startAddr;
  378.   bd := spaceRoot.next;
  379.   while bd <> @spaceRoot do begin
  380.     // Decommit the intersection of the block described by bd and [startAddr..endAddr)
  381.     loAddr := bd.addr;
  382.     hiAddr := loAddr + bd.size;
  383.     if loAddr < startAddr then
  384.       loAddr := startAddr;
  385.     if hiAddr > endAddr then
  386.       hiAddr := endAddr;
  387.     if loAddr < hiAddr then begin
  388.       if not VirtualFree(loAddr, hiAddr - loAddr, MEM_DECOMMIT) then
  389.     heapErrorCode := cDecommitErr;
  390.     end;
  391.     bd := bd.next;
  392.   end;
  393. end;
  394.  
  395.  
  396. //
  397. // Committed space administration
  398. //
  399. const
  400.   cCommitAlign = 16*1024;
  401.  
  402. var
  403.   decommittedRoot: TBlockDesc;
  404.  
  405.  
  406. function GetCommitted(minSize: Integer): TBlock;
  407. // Get a block of committed memory.
  408. // Returns a committed memory block, possibly much bigger than requested.
  409. // Will return a block with a nil addr on failure.
  410. var
  411.   bd: PBlockDesc;
  412. begin
  413.   minSize := (minSize + (cCommitAlign-1)) and not (cCommitAlign-1);
  414.   repeat
  415.     bd := decommittedRoot.next;
  416.     while bd <> @decommittedRoot do begin
  417.       if bd.size >= minSize then begin
  418.     result := Commit(bd.addr, minSize);
  419.     if result.addr = nil then
  420.       exit;
  421.     Inc(bd.addr, result.size);
  422.     Dec(bd.size, result.size);
  423.     if bd.size = 0 then
  424.       DeleteBlock(bd);
  425.     exit;
  426.       end;
  427.       bd := bd.next;
  428.     end;
  429.     result := GetSpace(minSize);
  430.     if result.addr = nil then
  431.       exit;
  432.     if MergeBlockAfter(@decommittedRoot, result).addr = nil then begin
  433.       FreeSpace(result.addr, result.size);
  434.       result.addr := nil;
  435.       exit;
  436.     end;
  437.   until False;
  438. end;
  439.  
  440.  
  441. function GetCommittedAt(addr: PChar; minSize: Integer): TBlock;
  442. // Get at least minSize bytes committed space at addr.
  443. // Success: returns a block, possibly much bigger than requested.
  444. // Failure: returns a block with addr = nil.
  445. var
  446.   bd: PBlockDesc;
  447.   b: TBlock;
  448. begin
  449.   minSize := (minSize + (cCommitAlign-1)) and not (cCommitAlign-1);
  450.   repeat
  451.  
  452.     bd := decommittedRoot.next;
  453.     while (bd <> @decommittedRoot) and (bd.addr <> addr) do
  454.       bd := bd.next;
  455.  
  456.     if bd.addr = addr then begin
  457.       if bd.size >= minSize then
  458.     break;
  459.       b := GetSpaceAt(bd.addr + bd.size, minSize - bd.size);
  460.       if b.addr <> nil then begin
  461.     if MergeBlockAfter(@decommittedRoot, b).addr <> nil then
  462.       continue
  463.     else begin
  464.       FreeSpace(b.addr, b.size);
  465.       result.addr := nil;
  466.       exit;
  467.     end;
  468.       end;
  469.     end;
  470.  
  471.     b := GetSpaceAt(addr, minSize);
  472.     if b.addr = nil then
  473.       break;
  474.  
  475.     if MergeBlockAfter(@decommittedRoot, b).addr = nil then begin
  476.       FreeSpace(b.addr, b.size);
  477.       result.addr := nil;
  478.       exit;
  479.     end;
  480.   until false;
  481.  
  482.   if (bd.addr = addr) and (bd.size >= minSize) then begin
  483.     result := Commit(bd.addr, minSize);
  484.     if result.addr = nil then
  485.       exit;
  486.     Inc(bd.addr, result.size);
  487.     Dec(bd.size, result.size);
  488.     if bd.size = 0 then
  489.       DeleteBlock(bd);
  490.   end else
  491.     result.addr := nil;
  492. end;
  493.  
  494.  
  495. function FreeCommitted(addr: PChar; maxSize: Integer): TBlock;
  496. // Free at most maxSize bytes of address space at addr.
  497. // Returns the block that was actually freed.
  498. var
  499.   startAddr, endAddr: PChar;
  500.   b: TBlock;
  501. begin
  502.   startAddr := PChar(Integer(addr + (cCommitAlign-1)) and not (cCommitAlign-1));
  503.   endAddr := PChar(Integer(addr + maxSize) and not (cCommitAlign-1));
  504.   if endAddr > startAddr then begin
  505.     result := Decommit(startAddr, endAddr - startAddr);
  506.     b := MergeBlockAfter(@decommittedRoot, result);
  507.     if b.addr <> nil then
  508.       b := FreeSpace(b.addr, b.size);
  509.     if b.addr <> nil then
  510.       RemoveBlock(@decommittedRoot, b);
  511.   end else
  512.     result.addr := nil;
  513. end;
  514.  
  515.  
  516. //
  517. // Suballocator (what the user program actually calls)
  518. //
  519.  
  520. type
  521.   PFree = ^TFree;
  522.   TFree = record
  523.     prev: PFree;
  524.     next: PFree;
  525.     size: Integer;
  526.   end;
  527.   PUsed = ^TUsed;
  528.   TUsed = record
  529.     sizeFlags: Integer;
  530.   end;
  531.  
  532. const
  533.   cAlign        = 4;
  534.   cThisUsedFlag = 2;
  535.   cPrevFreeFlag = 1;
  536.   cFillerFlag   = $80000000;
  537.   cFlags        = cThisUsedFlag or cPrevFreeFlag or cFillerFlag;
  538.   cSmallSize    = 4*1024;
  539.   cDecommitMin    = 15*1024;
  540.  
  541. type
  542.   TSmallTab    = array [sizeof(TFree) div cAlign .. cSmallSize div cAlign] of PFree;
  543.  
  544. VAR
  545.   avail        : TFree;
  546.   rover        : PFree;
  547.   remBytes     : Integer;
  548.   curAlloc     : PChar;
  549.   smallTab     : ^TSmallTab;
  550.   committedRoot: TBlockDesc;
  551.  
  552.  
  553. function InitAllocator: Boolean;
  554. // Initialize. No other calls legal before that.
  555. var
  556.   i: Integer;
  557.   a: PFree;
  558. begin
  559.   try
  560.     InitializeCriticalSection(heapLock);
  561.     if IsMultiThread then EnterCriticalSection(heapLock);
  562.  
  563.     MakeEmpty(@spaceRoot);
  564.     MakeEmpty(@decommittedRoot);
  565.     MakeEmpty(@committedRoot);
  566.  
  567.     smallTab := LocalAlloc(LMEM_FIXED, sizeof(smallTab^));
  568.     if smallTab <> nil then begin
  569.       for i:= low(smallTab^) to high(smallTab^) do
  570.     smallTab[i] := nil;
  571.  
  572.       a := @avail;
  573.       a.next := a;
  574.       a.prev := a;
  575.       rover := a;
  576.  
  577.       initialized := True;
  578.     end;
  579.   finally
  580.     if IsMultiThread then LeaveCriticalSection(heapLock);
  581.   end;
  582.   result := initialized;
  583. end;
  584.  
  585.  
  586. procedure UninitAllocator;
  587. // Shutdown.
  588. var
  589.   bdb: PBlockDescBlock;
  590.   bd : PBlockDesc;
  591. begin
  592.   if initialized then begin
  593.     try
  594.       if IsMultiThread then EnterCriticalSection(heapLock);
  595.  
  596.       initialized := False;
  597.  
  598.       LocalFree(smallTab);
  599.       smallTab := nil;
  600.  
  601.       bd := spaceRoot.next;
  602.       while bd <> @spaceRoot do begin
  603.     VirtualFree(bd.addr, 0, MEM_RELEASE);
  604.     bd := bd.next;
  605.       end;
  606.  
  607.       MakeEmpty(@spaceRoot);
  608.       MakeEmpty(@decommittedRoot);
  609.       MakeEmpty(@committedRoot);
  610.  
  611.       bdb := blockDescBlockList;
  612.       while bdb <> nil do begin
  613.     blockDescBlockList := bdb^.next;
  614.     LocalFree(bdb);
  615.         bdb := blockDescBlockList;
  616.       end;
  617.     finally
  618.       if IsMultiThread then LeaveCriticalSection(heapLock);
  619.       DeleteCriticalSection(heapLock);
  620.     end;
  621.   end;
  622. end;
  623.  
  624.  
  625. procedure DeleteFree(f: PFree);
  626. var
  627.   n, p: PFree;
  628.   size: Cardinal;
  629. begin
  630.   if rover = f then
  631.     rover := f.next;
  632.   n := f.next;
  633.   size := f.size;
  634.   if size <= cSmallSize then begin
  635.     if n = f then
  636.       smallTab[size div cAlign] := nil
  637.     else begin
  638.       smallTab[size div cAlign] := n;
  639.       p := f.prev;
  640.       n.prev := p;
  641.       p.next := n;
  642.     end;
  643.   end else begin
  644.     p := f.prev;
  645.     n.prev := p;
  646.     p.next := n;
  647.   end;
  648. end;
  649.  
  650.  
  651. procedure InsertFree(a: Pointer; size: Cardinal); forward;
  652.  
  653.  
  654. function FindCommitted(addr: PChar): PBlockDesc;
  655. begin
  656.   result := committedRoot.next;
  657.   while result <> @committedRoot do begin
  658.     if (addr >= result.addr) and (addr < result.addr + result.size) then
  659.       exit;
  660.     result := result.next;
  661.   end;
  662.   heapErrorCode := cBadCommittedList;
  663.   result := nil;
  664. end;
  665.  
  666.  
  667. procedure FillBeforeGap(a: PChar; size: Cardinal);
  668. var
  669.   rest: Cardinal;
  670.   e: PUsed;
  671. begin
  672.   rest := size - sizeof(TUsed);
  673.   e := PUsed(a + rest);
  674.   if size >= sizeof(TFree) + sizeof(TUsed) then begin
  675.     e.sizeFlags := sizeof(TUsed) or cThisUsedFlag or cPrevFreeFlag or cFillerFlag;
  676.     InsertFree(a, rest);
  677.   end else if size >= sizeof(TUsed) then begin
  678.     PUsed(a).sizeFlags := size or (cThisUsedFlag or cFillerFlag);
  679.     e.sizeFlags := size or (cThisUsedFlag or cFillerFlag);
  680.   end;
  681. end;
  682.  
  683.  
  684. procedure InternalFreeMem(a: PChar);
  685. begin
  686.   Inc(AllocMemCount);
  687.   Inc(AllocMemSize,PUsed(a-sizeof(TUsed)).sizeFlags and not cFlags - sizeof(TUsed));
  688.   SysFreeMem(a);
  689. end;
  690.  
  691.  
  692. procedure FillAfterGap(a: PChar; size: Cardinal);
  693. begin
  694.   if size >= sizeof(TFree) then begin
  695.     PUsed(a).sizeFlags := size or cThisUsedFlag;
  696.     InternalFreeMem(a + sizeof(TUsed));
  697.   end else begin
  698.     if size >= sizeof(TUsed) then
  699.       PUsed(a).sizeFlags := size or (cThisUsedFlag or cFillerFlag);
  700.     Inc(a,size);
  701.     PUsed(a).sizeFlags := PUsed(a).sizeFlags and not cPrevFreeFlag;
  702.   end;
  703. end;
  704.  
  705.  
  706. function FillerSizeBeforeGap(a: PChar): Cardinal;
  707. var
  708.   sizeFlags : Cardinal;
  709.   freeSize  : Cardinal;
  710.   f : PFree;
  711. begin
  712.   sizeFlags := PUsed(a - sizeof(TUsed)).sizeFlags;
  713.   if (sizeFlags and (cThisUsedFlag or cFillerFlag)) <> (cThisUsedFlag or cFillerFlag) then
  714.     heapErrorCode := cBadFiller1;
  715.   result := sizeFlags and not cFlags;
  716.   Dec(a, result);
  717.   if ((PUsed(a).sizeFlags xor sizeFlags) and not cPrevFreeFlag) <> 0 then
  718.     HeapErrorCode := cBadFiller2;
  719.   if (PUsed(a).sizeFlags and cPrevFreeFlag) <> 0 then begin
  720.     freeSize := PFree(a - sizeof(TFree)).size;
  721.     f := PFree(a - freeSize);
  722.     if f.size <> freeSize then
  723.       heapErrorCode := cBadFiller3;
  724.     DeleteFree(f);
  725.     Inc(result, freeSize);
  726.   end;
  727. end;
  728.  
  729.  
  730. function FillerSizeAfterGap(a: PChar): Cardinal;
  731. var
  732.   sizeFlags: Cardinal;
  733.   f : PFree;
  734. begin
  735.   result := 0;
  736.   sizeFlags := PUsed(a).sizeFlags;
  737.   if (sizeFlags and cFillerFlag) <> 0 then begin
  738.     sizeFlags := sizeFlags and not cFlags;
  739.     Inc(result,sizeFlags);
  740.     Inc(a, sizeFlags);
  741.     sizeFlags := PUsed(a).sizeFlags;
  742.   end;
  743.   if (sizeFlags and cThisUsedFlag) = 0 then begin
  744.     f := PFree(a);
  745.     DeleteFree(f);
  746.     Inc(result, f.size);
  747.     Inc(a, f.size);
  748.     PUsed(a).sizeFlags := PUsed(a).sizeFlags and not cPrevFreeFlag;
  749.   end;
  750. end;
  751.  
  752.  
  753. function DecommitFree(a: PChar; size: Cardinal): Boolean;
  754. var
  755.   b: TBlock;
  756.   bd: PBlockDesc;
  757. begin
  758.   bd := FindCommitted(a);
  759.   if bd.addr + bd.size - (a + size) <= sizeof(TFree) then
  760.     size := bd.addr + bd.size - a;
  761.  
  762.   if a - bd.addr < sizeof(TFree) then
  763.     b := FreeCommitted(bd.addr, size + (a - bd.addr))
  764.   else
  765.     b := FreeCommitted(a + sizeof(TUsed), size - sizeof(TUsed));
  766.  
  767.   if b.addr = nil then
  768.     result := False
  769.   else begin
  770.     FillBeforeGap(a, b.addr - a);
  771.     if bd.addr + bd.size > b.addr + b.size then
  772.       FillAfterGap(b.addr + b.size, a + size - (b.addr + b.size));
  773.     RemoveBlock(bd,b);
  774.     result := True;
  775.   end;
  776. end;
  777.  
  778.  
  779. procedure InsertFree(a: Pointer; size: Cardinal);
  780. var
  781.   f, n, p: PFree;
  782. begin
  783.   f := PFree(a);
  784.   f.size := size;
  785.   PFree(PChar(f) + size - sizeof(TFree)).size := size;
  786.   if size <= cSmallSize then begin
  787.     n := smallTab[size div cAlign];
  788.     if n = nil then begin
  789.       smallTab[size div cAlign] := f;
  790.       f.next := f;
  791.       f.prev := f;
  792.     end else begin
  793.       p := n.prev;
  794.       f.next := n;
  795.       f.prev := p;
  796.       n.prev := f;
  797.       p.next := f;
  798.     end;
  799.   end else if (size < cDecommitMin) or not DecommitFree(a, size) then begin
  800.     n := rover;
  801.     rover := f;
  802.     p := n.prev;
  803.     f.next := n;
  804.     f.prev := p;
  805.     n.prev := f;
  806.     p.next := f;
  807.   end;
  808. end;
  809.  
  810.  
  811. procedure FreeCurAlloc;
  812. begin
  813.   if remBytes > 0 then begin
  814.     if remBytes < sizeof(TFree) then
  815.       heapErrorCode := cBadCurAlloc
  816.     else begin
  817.       PUsed(curAlloc).sizeFlags := remBytes or cThisUsedFlag;
  818.       InternalFreeMem(curAlloc + sizeof(TUsed));
  819.       curAlloc := nil;
  820.       remBytes := 0;
  821.     end;
  822.   end;
  823. end;
  824.  
  825.  
  826. function MergeCommit(b: TBlock): Boolean;
  827. var
  828.   merged: TBlock;
  829.   fSize: Cardinal;
  830. begin
  831.   FreeCurAlloc;
  832.   merged := MergeBlockAfter(@committedRoot, b);
  833.   if merged.addr = nil then begin
  834.     result := False;
  835.     exit;
  836.   end;
  837.  
  838.   if merged.addr < b.addr then begin
  839.     fSize := FillerSizeBeforeGap(b.addr);
  840.     Dec(b.addr, fSize);
  841.     Inc(b.size, fSize);
  842.   end;
  843.  
  844.   if merged.addr + merged.size > b.addr + b.size then begin
  845.     fSize := FillerSizeAfterGap(b.addr + b.size);
  846.     Inc(b.size, fSize);
  847.   end;
  848.  
  849.   if merged.addr + merged.size = b.addr + b.size then begin
  850.     FillBeforeGap(b.addr + b.size - sizeof(TUsed), sizeof(TUsed));
  851.     Dec(b.size, sizeof(TUsed));
  852.   end;
  853.  
  854.   curAlloc := b.addr;
  855.   remBytes := b.size;
  856.  
  857.   result := True;
  858. end;
  859.  
  860.  
  861. function NewCommit(minSize: Cardinal): Boolean;
  862. var
  863.   b: TBlock;
  864. begin
  865.   b := GetCommitted(minSize+sizeof(TUsed));
  866.   result := (b.addr <> nil) and MergeCommit(b);
  867. end;
  868.  
  869.  
  870. function NewCommitAt(addr: Pointer; minSize: Cardinal): Boolean;
  871. var
  872.   b: TBlock;
  873. begin
  874.   b := GetCommittedAt(addr, minSize+sizeof(TUsed));
  875.   result := (b.addr <> nil) and MergeCommit(b);
  876. end;
  877.  
  878.  
  879. function SearchSmallBlocks(size: Cardinal): PFree;
  880. var
  881.   i: Cardinal;
  882. begin
  883.   result := nil;
  884.   for i := size div cAlign to High(smallTab^) do begin
  885.     result := smallTab[i];
  886.     if result <> nil then
  887.       exit;
  888.   end;
  889. end;
  890.  
  891.  
  892. function TryHarder(size: Cardinal): Pointer;
  893. var
  894.   u: PUsed; f:PFree; saveSize, rest: Cardinal;
  895. begin
  896.  
  897.   repeat
  898.  
  899.     f := avail.next;
  900.     if (size <= f.size) then
  901.       break;
  902.  
  903.     f := rover;
  904.     if f.size >= size then
  905.       break;
  906.  
  907.     saveSize := f.size;
  908.     f.size := size;
  909.     repeat
  910.       f := f.next
  911.     until f.size >= size;
  912.     rover.size := saveSize;
  913.     if f <> rover then begin
  914.       rover := f;
  915.       break;
  916.     end;
  917.  
  918.     if size <= cSmallSize then begin
  919.       f := SearchSmallBlocks(size);
  920.       if f <> nil then
  921.     break;
  922.     end;
  923.  
  924.     if not NewCommit(size) then begin
  925.       result := nil;
  926.       exit;
  927.     end;
  928.  
  929.     if remBytes >= size then begin
  930.       Dec(remBytes, size);
  931.       if remBytes < sizeof(TFree) then begin
  932.     Inc(size, remBytes);
  933.     remBytes := 0;
  934.       end;
  935.       u := PUsed(curAlloc);
  936.       Inc(curAlloc, size);
  937.       u.sizeFlags := size or cThisUsedFlag;
  938.       result := PChar(u) + sizeof(TUsed);
  939.       Inc(AllocMemCount);
  940.       Inc(AllocMemSize,size - sizeof(TUsed));
  941.       exit;
  942.     end;
  943.  
  944.   until False;
  945.  
  946.   DeleteFree(f);
  947.  
  948.   rest := f.size - size;
  949.   if rest >= sizeof(TFree) then begin
  950.     InsertFree(PChar(f) + size, rest);
  951.   end else begin
  952.     size := f.size;
  953.     if f = rover then
  954.       rover := f.next;
  955.     u := PUsed(PChar(f) + size);
  956.     u.sizeFlags := u.sizeFlags and not cPrevFreeFlag;
  957.   end;
  958.  
  959.   u := PUsed(f);
  960.   u.sizeFlags := size or cThisUsedFlag;
  961.  
  962.   result := PChar(u) + sizeof(TUsed);
  963.   Inc(AllocMemCount);
  964.   Inc(AllocMemSize,size - sizeof(TUsed));
  965.  
  966. end;
  967.  
  968.  
  969. function SysGetMem(size: Integer): Pointer;
  970. // Allocate memory block.
  971. var
  972.   f, prev, next: PFree;
  973.   u: PUsed;
  974. begin
  975.  
  976.   if not initialized and not InitAllocator then begin
  977.     result := nil;
  978.     exit;
  979.   end;
  980.  
  981.   try
  982.     if IsMultiThread then EnterCriticalSection(heapLock);
  983.  
  984.     Inc(size, sizeof(TUsed) + (cAlign-1));
  985.     size := size and not (cAlign-1);
  986.     if size < sizeof(TFree) then
  987.       size := sizeof(TFree);
  988.  
  989.     if size <= cSmallSize then begin
  990.       f := smallTab[size div cAlign];
  991.       if f <> nil then begin
  992.     u := PUsed(PChar(f) + size);
  993.     u.sizeFlags := u.sizeFlags and not cPrevFreeFlag;
  994.     next := f.next;
  995.     if next = f then
  996.       smallTab[size div cAlign] := nil
  997.     else begin
  998.       smallTab[size div cAlign] := next;
  999.       prev := f.prev;
  1000.       prev.next := next;
  1001.       next.prev := prev;
  1002.     end;
  1003.     u := PUsed(f);
  1004.     u.sizeFlags := f.size or cThisUsedFlag;
  1005.     result := PChar(u) + sizeof(TUsed);
  1006.     Inc(AllocMemCount);
  1007.     Inc(AllocMemSize,size - sizeof(TUsed));
  1008.     exit;
  1009.       end;
  1010.     end;
  1011.  
  1012.     if size <= remBytes then begin
  1013.       Dec(remBytes, size);
  1014.       if remBytes < sizeof(TFree) then begin
  1015.     Inc(size, remBytes);
  1016.     remBytes := 0;
  1017.       end;
  1018.       u := PUsed(curAlloc);
  1019.       Inc(curAlloc, size);
  1020.       u.sizeFlags := size or cThisUsedFlag;
  1021.       result := PChar(u) + sizeof(TUsed);
  1022.       Inc(AllocMemCount);
  1023.       Inc(AllocMemSize,size - sizeof(TUsed));
  1024.       exit;
  1025.     end;
  1026.  
  1027.     result := TryHarder(size);
  1028.  
  1029.   finally
  1030.     if IsMultiThread then LeaveCriticalSection(heapLock);
  1031.   end;
  1032.  
  1033. end;
  1034.  
  1035.  
  1036. function SysFreeMem(p: Pointer): Integer;
  1037. // Deallocate memory block.
  1038. label
  1039.   abort;
  1040. var
  1041.   u, n : PUsed;
  1042.   f : PFree;
  1043.   prevSize, nextSize, size : Cardinal;
  1044. begin
  1045.   heapErrorCode := cHeapOk;
  1046.  
  1047.   if not initialized and not InitAllocator then begin
  1048.     heapErrorCode := cCantInit;
  1049.     result := cCantInit;
  1050.     exit;
  1051.   end;
  1052.  
  1053.   try
  1054.     if IsMultiThread then EnterCriticalSection(heapLock);
  1055.  
  1056.     u := p;
  1057.     u := PUsed(PChar(u) - sizeof(TUsed));
  1058.  
  1059.     size := u.sizeFlags;
  1060.     if (size and cThisUsedFlag) = 0 then begin
  1061.       heapErrorCode := cBadUsedBlock;
  1062.       goto abort;
  1063.     end;
  1064.  
  1065.     Dec(AllocMemCount);
  1066.     Dec(AllocMemSize,size and not cFlags - sizeof(TUsed));
  1067.  
  1068.     if (size and cPrevFreeFlag) <> 0 then begin
  1069.       prevSize := PFree(PChar(u)-sizeof(TFree)).size;
  1070.       if (prevSize < sizeof(TFree)) or ((prevSize and cFlags) <> 0) then begin
  1071.     heapErrorCode := cBadPrevBlock;
  1072.     goto abort;
  1073.       end;
  1074.  
  1075.       f := PFree(PChar(u) - prevSize);
  1076.       if f^.size <> prevSize then begin
  1077.     heapErrorCode := cBadPrevBlock;
  1078.     goto abort;
  1079.       end;
  1080.  
  1081.       inc(size, prevSize);
  1082.       u := PUsed(f);
  1083.       DeleteFree(f);
  1084.     end;
  1085.  
  1086.     size := size and not cFlags;
  1087.     n := PUsed(PChar(u) + size);
  1088.  
  1089.     if PChar(n) = curAlloc then begin
  1090.       dec(curAlloc, size);
  1091.       inc(remBytes, size);
  1092.       if remBytes > cDecommitMin then
  1093.     FreeCurAlloc;
  1094.       result := cHeapOk;
  1095.       exit;
  1096.     end;
  1097.  
  1098.     if (n.sizeFlags and cThisUsedFlag) <> 0 then begin
  1099.       if (n.sizeFlags and not cFlags) < sizeof(TUsed) then begin
  1100.     heapErrorCode := cBadNextBlock;
  1101.     goto abort;
  1102.       end;
  1103.       n.sizeFlags := n.sizeFlags or cPrevFreeFlag
  1104.     end else begin
  1105.       f := PFree(n);
  1106.       if (f.next = nil) or (f.prev = nil) or (f.size < sizeof(TFree)) then begin
  1107.     heapErrorCode := cBadNextBlock;
  1108.     goto abort;
  1109.       end;
  1110.       nextSize := f.size;
  1111.       inc(size,nextSize);
  1112.       DeleteFree(f);
  1113.     end;
  1114.  
  1115.     InsertFree(u, size);
  1116. abort:
  1117.     result := heapErrorCode;
  1118.   finally
  1119.     if IsMultiThread then LeaveCriticalSection(heapLock);
  1120.   end;
  1121. end;
  1122.  
  1123.  
  1124. function ResizeInPlace(p: Pointer; newSize: Cardinal): Boolean;
  1125. var u, n: PUsed; f: PFree; oldSize, blkSize, neededSize: Cardinal;
  1126. begin
  1127.   Inc(newSize, sizeof(TUsed)+cAlign-1);
  1128.   newSize := newSize and not (cAlign-1);
  1129.   if newSize < sizeof(TFree) then
  1130.     newSize := sizeof(TFree);
  1131.   u := PUsed(PChar(p) - sizeof(TUsed));
  1132.   oldSize := u.sizeFlags and not cFlags;
  1133.   n := PUsed( PChar(u) + oldSize );
  1134.   if newSize <= oldSize then begin
  1135.     blkSize := oldSize - newSize;
  1136.     if PChar(n) = curAlloc then begin
  1137.       Dec(curAlloc, blkSize);
  1138.       Inc(remBytes, blkSize);
  1139.       if remBytes < sizeof(TFree) then begin
  1140.     Inc(curAlloc, blkSize);
  1141.     Dec(remBytes, blkSize);
  1142.     newSize := oldSize;
  1143.       end;
  1144.     end else begin
  1145.       n := PUsed(PChar(u) + oldSize);
  1146.       if n.sizeFlags and cThisUsedFlag = 0 then begin
  1147.     f := PFree(n);
  1148.     Inc(blkSize, f.size);
  1149.     DeleteFree(f);
  1150.       end;
  1151.       if blkSize >= sizeof(TFree) then begin
  1152.     n := PUsed(PChar(u) + newSize);
  1153.     n.sizeFlags := blkSize or cThisUsedFlag;
  1154.     InternalFreeMem(PChar(n) + sizeof(TUsed));
  1155.       end else
  1156.     newSize := oldSize;
  1157.     end;
  1158.   end else begin
  1159.     repeat
  1160.       neededSize := newSize - oldSize;
  1161.       if PChar(n) = curAlloc then begin
  1162.     if remBytes >= neededSize then begin
  1163.       Dec(remBytes, neededSize);
  1164.       Inc(curAlloc, neededSize);
  1165.       if remBytes < sizeof(TFree) then begin
  1166.         Inc(curAlloc, remBytes);
  1167.         Inc(newSize, remBytes);
  1168.         remBytes := 0;
  1169.       end;
  1170.           Inc(AllocMemSize, newSize - oldSize);
  1171.       u.sizeFlags := newSize or u.sizeFlags and cFlags;
  1172.       result := true;
  1173.       exit;
  1174.     end else begin
  1175.       FreeCurAlloc;
  1176.       n := PUsed( PChar(u) + oldSize );
  1177.     end;
  1178.       end;
  1179.  
  1180.       if n.sizeFlags and cThisUsedFlag = 0 then begin
  1181.     f := PFree(n);
  1182.     blkSize := f.size;
  1183.     if blkSize < neededSize then begin
  1184.       n := PUsed(PChar(n) + blkSize);
  1185.       Dec(neededSize, blkSize);
  1186.     end else begin
  1187.       DeleteFree(f);
  1188.       Dec(blkSize, neededSize);
  1189.       if blkSize >= sizeof(TFree) then
  1190.         InsertFree(PChar(u) + newSize, blkSize)
  1191.       else begin
  1192.         Inc(newSize, blkSize);
  1193.         n := PUsed(PChar(u) + newSize);
  1194.         n.sizeFlags := n.sizeFlags and not cPrevFreeFlag;
  1195.       end;
  1196.       break;
  1197.     end;
  1198.       end;
  1199.  
  1200.       if n.sizeFlags and cFillerFlag <> 0 then begin
  1201.     n := PUsed(PChar(n) + n.sizeFlags and not cFlags);
  1202.     if NewCommitAt(n, neededSize) then begin
  1203.       n := PUsed( PChar(u) + oldSize );
  1204.       continue;
  1205.     end;
  1206.       end;
  1207.  
  1208.       result := False;
  1209.       exit;
  1210.  
  1211.     until False;
  1212.  
  1213.   end;
  1214.  
  1215.   Inc(AllocMemSize, newSize - oldSize);
  1216.   u.sizeFlags := newSize or u.sizeFlags and cFlags;
  1217.   result := True;
  1218.  
  1219. end;
  1220.  
  1221.  
  1222. function SysReallocMem(p: Pointer; size: Integer): Pointer;
  1223. // Resize memory block.
  1224. var
  1225.   n: Pointer; oldSize: Cardinal;
  1226. begin
  1227.  
  1228.   if not initialized and not InitAllocator then begin
  1229.     result := nil;
  1230.     exit;
  1231.   end;
  1232.  
  1233.   try
  1234.     if IsMultiThread then EnterCriticalSection(heapLock);
  1235.  
  1236.     if ResizeInPlace(p, size) then
  1237.       result := p
  1238.     else begin
  1239.       n := SysGetMem(size);
  1240.       oldSize := (PUsed(PChar(p)-sizeof(PUsed)).sizeFlags and not cFlags) - sizeof(TUsed);
  1241.       if oldSize > size then
  1242.     oldSize := size;
  1243.       if n <> nil then begin
  1244.     Move(p^, n^, oldSize);
  1245.     SysFreeMem(p);
  1246.       end;
  1247.       result := n;
  1248.     end;
  1249.   finally
  1250.     if IsMultiThread then LeaveCriticalSection(heapLock);
  1251.   end;
  1252.  
  1253. end;
  1254.  
  1255.  
  1256. function BlockSum(root: PBlockDesc): Cardinal;
  1257. var
  1258.   b : PBlockDesc;
  1259. begin
  1260.   result := 0;
  1261.   b := root.next;
  1262.   while b <> root do begin
  1263.     Inc(result, b.size);
  1264.     b := b.next;
  1265.   end;
  1266. end;
  1267.  
  1268.  
  1269. function GetHeapStatus: THeapStatus;
  1270. var
  1271.   size, freeSize, userSize: Cardinal;
  1272.   f: PFree;
  1273.   a, e: PChar;
  1274.   i: Integer;
  1275.   b: PBlockDesc;
  1276.   prevFree: Boolean;
  1277. begin
  1278.  
  1279.   heapErrorCode := cHeapOk;
  1280.  
  1281.   result.TotalAddrSpace   := 0;
  1282.   result.TotalUncommitted := 0;
  1283.   result.TotalCommitted   := 0;
  1284.   result.TotalAllocated   := 0;
  1285.   result.TotalFree        := 0;
  1286.   result.FreeSmall        := 0;
  1287.   result.FreeBig          := 0;
  1288.   result.Unused           := 0;
  1289.   result.Overhead         := 0;
  1290.   result.HeapErrorCode    := cHeapOk;
  1291.  
  1292.   if not initialized then exit;
  1293.  
  1294.   try
  1295.     if IsMultiThread then EnterCriticalSection(heapLock);
  1296.  
  1297.     result.totalAddrSpace   := BlockSum(@spaceRoot);
  1298.     result.totalUncommitted := BlockSum(@decommittedRoot);
  1299.     result.totalCommitted   := BlockSum(@committedRoot);
  1300.  
  1301.     size := 0;
  1302.     for i := Low(smallTab^) to High(smallTab^) do begin
  1303.       f := smallTab[i];
  1304.       if f <> nil then begin
  1305.     repeat
  1306.       Inc(size, f.size);
  1307.       if (f.prev.next <> f) or (f.next.prev <> f) or (f.size < sizeof(TFree)) then begin
  1308.         heapErrorCode := cBadFreeList;
  1309.         break;
  1310.       end;
  1311.       f := f.next;
  1312.     until f = smallTab[i];
  1313.       end;
  1314.     end;
  1315.     result.freeSmall := size;
  1316.  
  1317.     size := 0;
  1318.     f := avail.next;
  1319.     while f <> @avail do begin
  1320.       if (f.prev.next <> f) or (f.next.prev <> f) or (f.size < sizeof(TFree)) then begin
  1321.     heapErrorCode := cBadFreeList;
  1322.     break;
  1323.       end;
  1324.       Inc(size, f.size);
  1325.       f := f.next;
  1326.     end;
  1327.     result.freeBig := size;
  1328.  
  1329.     result.unused := remBytes;
  1330.     result.totalFree := result.freeSmall + result.freeBig + result.unused;
  1331.  
  1332.     freeSize := 0;
  1333.     userSize := 0;
  1334.     result.overhead := 0;
  1335.  
  1336.     b := committedRoot.next;
  1337.     prevFree := False;
  1338.     while b <> @committedRoot do begin
  1339.       a := b.addr;
  1340.       e := a + b.size;
  1341.       while a < e do begin
  1342.     if (a = curAlloc) and (remBytes > 0) then begin
  1343.       size := remBytes;
  1344.       Inc(freeSize, size);
  1345.       if prevFree then
  1346.         heapErrorCode := cBadCurAlloc;
  1347.       prevFree := False;
  1348.     end else begin
  1349.       if prevFree <> ((PUsed(a).sizeFlags and cPrevFreeFlag) <> 0) then
  1350.         heapErrorCode := cBadNextBlock;
  1351.       if (PUsed(a).sizeFlags and cThisUsedFlag) = 0 then begin
  1352.         f := PFree(a);
  1353.         if (f.prev.next <> f) or (f.next.prev <> f) or (f.size < sizeof(TFree)) then
  1354.           heapErrorCode := cBadFreeBlock;
  1355.         size := f.size;
  1356.         Inc(freeSize, size);
  1357.         prevFree := True;
  1358.       end else begin
  1359.         size := PUsed(a).sizeFlags and not cFlags;
  1360.         if (PUsed(a).sizeFlags and cFillerFlag) <> 0 then begin
  1361.           Inc(result.overhead, size);
  1362.           if (a > b.addr) and (a + size < e) then
  1363.         heapErrorCode := cBadUsedBlock;
  1364.         end else begin
  1365.           Inc(userSize, size-sizeof(TUsed));
  1366.           Inc(result.overhead, sizeof(TUsed));
  1367.         end;
  1368.         prevFree := False;
  1369.       end;
  1370.     end;
  1371.     Inc(a, size);
  1372.       end;
  1373.       b := b.next;
  1374.     end;
  1375.     if result.totalFree <> freeSize then
  1376.       heapErrorCode := cBadBalance;
  1377.  
  1378.     result.totalAllocated := userSize;
  1379.     result.heapErrorCode := heapErrorCode;
  1380.   finally
  1381.     if IsMultiThread then LeaveCriticalSection(heapLock);
  1382.   end;
  1383. end;
  1384.  
  1385.