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