heap.inc 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by the Free Pascal development team.
  4. functions for heap management in the data segment
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {****************************************************************************}
  12. { Do not use standard memory manager }
  13. { Custom memory manager is Multi Threaded and does not require locking }
  14. { define HAS_MT_MEMORYMANAGER}
  15. { Do not use standard memory manager }
  16. { Custom memory manager requires locking when threading is used }
  17. { define HAS_MEMORYMANAGER}
  18. { Try to find the best matching block in general freelist }
  19. { define BESTMATCH}
  20. { DEBUG: Dump info when the heap needs to grow }
  21. { define DUMPGROW}
  22. { Memory profiling: at moment in time of max heap size usage,
  23. keep statistics of number of each size allocated
  24. (with 16 byte granularity) }
  25. { define DUMP_MEM_USAGE}
  26. {$ifdef HAS_MT_MEMORYMANAGER}
  27. {$define HAS_MEMORYMANAGER}
  28. {$endif HAS_MT_MEMORYMANAGER}
  29. {$ifdef DUMP_MEM_USAGE}
  30. {$define SHOW_MEM_USAGE}
  31. {$endif}
  32. const
  33. {$ifdef CPU64}
  34. blocksize = 32; { at least size of freerecord }
  35. blockshift = 5; { shr value for blocksize=2^blockshift}
  36. maxblocksize = 512+blocksize; { 1024+8 needed for heaprecord }
  37. {$else}
  38. blocksize = 16; { at least size of freerecord }
  39. blockshift = 4; { shr value for blocksize=2^blockshift}
  40. maxblocksize = 512+blocksize; { 1024+8 needed for heaprecord }
  41. {$endif}
  42. maxblockindex = maxblocksize div blocksize; { highest index in array of lists of memchunks }
  43. maxreusebigger = 8; { max reuse bigger tries }
  44. { common flags }
  45. fixedsizeflag = 1; { flag if the block is of fixed size }
  46. { memchunk var flags }
  47. usedflag = 2; { flag if the block is used or not }
  48. lastblockflag = 4; { flag if the block is the last in os chunk }
  49. firstblockflag = 8; { flag if the block is the first in os chunk }
  50. { os chunk flags }
  51. ocrecycleflag = 1;
  52. { above flags stored in size field }
  53. sizemask = not(blocksize-1);
  54. fixedoffsetshift = 16;
  55. fixedsizemask = sizemask and ((1 shl fixedoffsetshift) - 1);
  56. {****************************************************************************}
  57. {$ifdef DUMPGROW}
  58. {$define DUMPBLOCKS}
  59. {$endif}
  60. { Memory manager }
  61. const
  62. MemoryManager: TMemoryManager = (
  63. {$ifdef HAS_MT_MEMORYMANAGER}
  64. NeedLock: false;
  65. {$else HAS_MT_MEMORYMANAGER}
  66. NeedLock: true;
  67. {$endif HAS_MT_MEMORYMANAGER}
  68. GetMem: @SysGetMem;
  69. FreeMem: @SysFreeMem;
  70. FreeMemSize: @SysFreeMemSize;
  71. AllocMem: @SysAllocMem;
  72. ReAllocMem: @SysReAllocMem;
  73. MemSize: @SysMemSize;
  74. InitThread: nil;
  75. DoneThread: nil;
  76. RelocateHeap: nil;
  77. GetHeapStatus: @SysGetHeapStatus;
  78. GetFPCHeapStatus: @SysGetFPCHeapStatus;
  79. );
  80. {$ifndef HAS_MEMORYMANAGER}
  81. {
  82. We use 'fixed' size chunks for small allocations,
  83. and os chunks with variable sized blocks for big
  84. allocations.
  85. * a block is an area allocated by user
  86. * a chunk is a block plus our bookkeeping
  87. * an os chunk is a collection of chunks
  88. Memory layout:
  89. fixed: < chunk size > [ ... user data ... ]
  90. variable: < prev chunk size > < chunk size > [ ... user data ... ]
  91. When all chunks in an os chunk are free, we keep a few around
  92. but otherwise it will be freed to the OS.
  93. Fixed os chunks can be converted to variable os chunks and back
  94. (if not too big). To prevent repeated conversion overhead in case
  95. of user freeing/allocing same or a small set of sizes, we only do
  96. the conversion to the new fixed os chunk size format after we
  97. reuse the os chunk for another fixed size, or variable. Note that
  98. while the fixed size os chunk is on the freelists.osfirst, it is also
  99. still present in a freelists.fixedlists, therefore we can easily remove
  100. the os chunk from the freelists.osfirst if this size is needed again; we
  101. don't need to search freelists.osfirst in alloc_oschunk, since it won't
  102. be present anymore if alloc_oschunk is reached. Note that removing
  103. from the freelists.osfirst is not really done, only the recycleflag is
  104. set, allowing to reset the flag easily. alloc_oschunk will clean up
  105. the list while passing over it, that was a slow function anyway.
  106. }
  107. type
  108. pfreelists = ^tfreelists;
  109. poschunk = ^toschunk;
  110. toschunk = record
  111. size : ptrint;
  112. next : poschunk;
  113. used : ptrint;
  114. freelists : pfreelists;
  115. { padding inserted automatically by alloc_oschunk }
  116. end;
  117. ppmemchunk_fixed = ^pmemchunk_fixed;
  118. pmemchunk_fixed = ^tmemchunk_fixed;
  119. tmemchunk_fixed = record
  120. { aligning is done automatically in alloc_oschunk }
  121. size : ptrint;
  122. next_fixed,
  123. prev_fixed : pmemchunk_fixed;
  124. end;
  125. ppmemchunk_var = ^pmemchunk_var;
  126. pmemchunk_var = ^tmemchunk_var;
  127. tmemchunk_var = record
  128. prevsize : ptrint;
  129. freelists : pfreelists;
  130. size : ptrint;
  131. next_var,
  132. prev_var : pmemchunk_var;
  133. end;
  134. { ``header'', ie. size of structure valid when chunk is in use }
  135. { should correspond to tmemchunk_var_hdr structure starting with the
  136. last field. Reason is that the overlap is starting from the end of the
  137. record. }
  138. tmemchunk_fixed_hdr = record
  139. { aligning is done automatically in alloc_oschunk }
  140. size : ptrint;
  141. end;
  142. tmemchunk_var_hdr = record
  143. prevsize : ptrint;
  144. freelists : pfreelists;
  145. size : ptrint;
  146. end;
  147. pfpcheapstatus = ^tfpcheapstatus;
  148. tfixedfreelists = array[1..maxblockindex] of pmemchunk_fixed;
  149. tfreelists = record
  150. osfirst : poschunk;
  151. oslast : poschunk;
  152. oscount : dword;
  153. fixedlists : tfixedfreelists;
  154. varlist : pmemchunk_var;
  155. { chunks waiting to be freed from other thread }
  156. waitfixed : pmemchunk_fixed;
  157. lockfixed : trtlcriticalsection;
  158. waitvar : pmemchunk_var;
  159. lockvar : trtlcriticalsection;
  160. { heap statistics }
  161. internal_status : TFPCHeapStatus;
  162. end;
  163. const
  164. fixedfirstoffset = ((sizeof(toschunk) + sizeof(tmemchunk_fixed_hdr) + $f)
  165. and not $f) - sizeof(tmemchunk_fixed_hdr);
  166. varfirstoffset = ((sizeof(toschunk) + sizeof(tmemchunk_var_hdr) + $f)
  167. and not $f) - sizeof(tmemchunk_var_hdr);
  168. {$ifdef BESTMATCH}
  169. matcheffort = high(longint);
  170. {$else}
  171. matcheffort = 10;
  172. {$endif}
  173. var
  174. main_orig_freelists : pfreelists;
  175. main_relo_freelists : pfreelists;
  176. threadvar
  177. freelists : tfreelists;
  178. {$ifdef DUMP_MEM_USAGE}
  179. const
  180. sizeusageshift = 4;
  181. sizeusageindex = 2049;
  182. sizeusagesize = sizeusageindex shl sizeusageshift;
  183. type
  184. tsizeusagelist = array[0..sizeusageindex] of longint;
  185. threadvar
  186. sizeusage, maxsizeusage: tsizeusagelist;
  187. {$endif}
  188. {$endif HAS_MEMORYMANAGER}
  189. {*****************************************************************************
  190. Memory Manager
  191. *****************************************************************************}
  192. procedure GetMemoryManager(var MemMgr:TMemoryManager);
  193. begin
  194. MemMgr := MemoryManager;
  195. end;
  196. procedure SetMemoryManager(const MemMgr:TMemoryManager);
  197. begin
  198. MemoryManager := MemMgr;
  199. end;
  200. function IsMemoryManagerSet:Boolean;
  201. begin
  202. IsMemoryManagerSet := (MemoryManager.GetMem<>@SysGetMem)
  203. or (MemoryManager.FreeMem<>@SysFreeMem);
  204. end;
  205. procedure GetMem(Var p:pointer;Size:ptrint);
  206. begin
  207. p := MemoryManager.GetMem(Size);
  208. end;
  209. procedure GetMemory(Var p:pointer;Size:ptrint);
  210. begin
  211. GetMem(p,size);
  212. end;
  213. procedure FreeMem(p:pointer;Size:ptrint);
  214. begin
  215. MemoryManager.FreeMemSize(p,Size);
  216. end;
  217. procedure FreeMemory(p:pointer;Size:ptrint);
  218. begin
  219. FreeMem(p,size);
  220. end;
  221. function GetHeapStatus:THeapStatus;
  222. begin
  223. Result:=MemoryManager.GetHeapStatus();
  224. end;
  225. function GetFPCHeapStatus:TFPCHeapStatus;
  226. begin
  227. Result:=MemoryManager.GetFPCHeapStatus();
  228. end;
  229. function MemSize(p:pointer):ptrint;
  230. begin
  231. MemSize := MemoryManager.MemSize(p);
  232. end;
  233. { Delphi style }
  234. function FreeMem(p:pointer):ptrint;[Public,Alias:'FPC_FREEMEM_X'];
  235. begin
  236. FreeMem := MemoryManager.FreeMem(p);
  237. end;
  238. function FreeMemory(p:pointer):ptrint;
  239. begin
  240. FreeMemory := FreeMem(p);
  241. end;
  242. function GetMem(size:ptrint):pointer;
  243. begin
  244. GetMem := MemoryManager.GetMem(Size);
  245. end;
  246. function GetMemory(size:ptrint):pointer;
  247. begin
  248. GetMemory := GetMem(size);
  249. end;
  250. function AllocMem(Size:ptrint):pointer;
  251. begin
  252. AllocMem := MemoryManager.AllocMem(size);
  253. end;
  254. function ReAllocMem(var p:pointer;Size:ptrint):pointer;
  255. begin
  256. ReAllocMem := MemoryManager.ReAllocMem(p,size);
  257. end;
  258. function ReAllocMemory(var p:pointer;Size:ptrint):pointer;
  259. begin
  260. ReAllocMemory := ReAllocMem(p,size);
  261. end;
  262. { Needed for calls from Assembler }
  263. function fpc_getmem(size:ptrint):pointer;compilerproc;[public,alias:'FPC_GETMEM'];
  264. begin
  265. fpc_GetMem := MemoryManager.GetMem(size);
  266. end;
  267. procedure fpc_freemem(p:pointer);compilerproc;[public,alias:'FPC_FREEMEM'];
  268. begin
  269. MemoryManager.FreeMem(p);
  270. end;
  271. {$ifndef HAS_MEMORYMANAGER}
  272. {*****************************************************************************
  273. GetHeapStatus
  274. *****************************************************************************}
  275. function SysGetFPCHeapStatus:TFPCHeapStatus;
  276. var
  277. status: pfpcheapstatus;
  278. begin
  279. status := @freelists.internal_status;
  280. status^.CurrHeapFree := status^.CurrHeapSize - status^.CurrHeapUsed;
  281. result := status^;
  282. end;
  283. function SysGetHeapStatus :THeapStatus;
  284. var
  285. status: pfpcheapstatus;
  286. begin
  287. status := @freelists.internal_status;
  288. status^.CurrHeapFree := status^.CurrHeapSize - status^.CurrHeapUsed;
  289. result.TotalAllocated :=status^.CurrHeapUsed;
  290. result.TotalFree :=status^.CurrHeapFree;
  291. result.TotalAddrSpace :=0;
  292. result.TotalUncommitted :=0;
  293. result.TotalCommitted :=0;
  294. result.FreeSmall :=0;
  295. result.FreeBig :=0;
  296. result.Unused :=0;
  297. result.Overhead :=0;
  298. result.HeapErrorCode :=0;
  299. end;
  300. {$ifdef DUMPBLOCKS} // TODO
  301. procedure DumpBlocks(loc_freelists: pfreelists);
  302. var
  303. s,i,j : ptrint;
  304. hpfixed : pmemchunk_fixed;
  305. hpvar : pmemchunk_var;
  306. begin
  307. { fixed freelist }
  308. for i := 1 to maxblockindex do
  309. begin
  310. hpfixed := loc_freelists^.fixedlists[i];
  311. j := 0;
  312. while assigned(hpfixed) do
  313. begin
  314. inc(j);
  315. hpfixed := hpfixed^.next_fixed;
  316. end;
  317. writeln('Block ',i*blocksize,': ',j);
  318. end;
  319. { var freelist }
  320. hpvar := loc_freelists^.varlist;
  321. j := 0;
  322. s := 0;
  323. while assigned(hpvar) do
  324. begin
  325. inc(j);
  326. if hpvar^.size>s then
  327. s := hpvar^.size;
  328. hpvar := hpvar^.next_var;
  329. end;
  330. writeln('Variable: ',j,' maxsize: ',s);
  331. end;
  332. {$endif}
  333. {*****************************************************************************
  334. List adding/removal
  335. *****************************************************************************}
  336. procedure append_to_list_var(pmc: pmemchunk_var); inline;
  337. var
  338. varlist: ppmemchunk_var;
  339. begin
  340. varlist := @pmc^.freelists^.varlist;
  341. pmc^.prev_var := nil;
  342. pmc^.next_var := varlist^;
  343. if varlist^<>nil then
  344. varlist^^.prev_var := pmc;
  345. varlist^ := pmc;
  346. end;
  347. {$ifdef HEAP_DEBUG}
  348. function find_fixed_mc(loc_freelists: pfreelists; chunkindex: ptrint;
  349. pmc: pmemchunk_fixed): boolean;
  350. var
  351. pmc_temp: pmemchunk_fixed;
  352. begin
  353. pmc_temp := loc_freelists^.fixedlists[chunkindex];
  354. while pmc_temp <> nil do
  355. begin
  356. if pmc_temp = pmc then exit(true);
  357. pmc_temp := pmc_temp^.next_fixed;
  358. end;
  359. result := false;
  360. end;
  361. {$endif}
  362. procedure remove_from_list_fixed(pmc: pmemchunk_fixed; fixedlist: ppmemchunk_fixed); inline;
  363. begin
  364. if assigned(pmc^.next_fixed) then
  365. pmc^.next_fixed^.prev_fixed := pmc^.prev_fixed;
  366. if assigned(pmc^.prev_fixed) then
  367. pmc^.prev_fixed^.next_fixed := pmc^.next_fixed
  368. else
  369. fixedlist^ := pmc^.next_fixed;
  370. end;
  371. procedure remove_from_list_var(pmc: pmemchunk_var); inline;
  372. begin
  373. if assigned(pmc^.next_var) then
  374. pmc^.next_var^.prev_var := pmc^.prev_var;
  375. if assigned(pmc^.prev_var) then
  376. pmc^.prev_var^.next_var := pmc^.next_var
  377. else
  378. freelists.varlist := pmc^.next_var;
  379. end;
  380. procedure remove_all_from_list_fixed(chunksize: ptrint; poc: poschunk);
  381. var
  382. pmc, pmc_end: pmemchunk_fixed;
  383. fixedlist: ppmemchunk_fixed;
  384. begin
  385. pmc := pmemchunk_fixed(pointer(poc)+fixedfirstoffset);
  386. pmc_end := pmemchunk_fixed(pointer(poc)+(poc^.size and sizemask)-chunksize);
  387. fixedlist := @poc^.freelists^.fixedlists[chunksize shr blockshift];
  388. repeat
  389. remove_from_list_fixed(pmc, fixedlist);
  390. pmc := pointer(pmc)+chunksize;
  391. until pmc > pmc_end;
  392. end;
  393. procedure append_to_oslist(poc: poschunk; chunksize: ptrint);
  394. var
  395. pocsize: ptrint;
  396. loc_freelists: pfreelists;
  397. begin
  398. loc_freelists := poc^.freelists;
  399. { check if already on list }
  400. if (poc^.size and ocrecycleflag) <> 0 then
  401. begin
  402. inc(loc_freelists^.oscount);
  403. poc^.size := poc^.size and not ocrecycleflag;
  404. exit;
  405. end;
  406. { decide whether to free block or add to list }
  407. {$ifdef HAS_SYSOSFREE}
  408. pocsize := poc^.size and sizemask;
  409. if (loc_freelists^.oscount >= MaxKeptOSChunks) or
  410. (pocsize > growheapsize2) then
  411. begin
  412. if chunksize <> 0 then
  413. remove_all_from_list_fixed(chunksize, poc);
  414. dec(loc_freelists^.internal_status.currheapsize, pocsize);
  415. SysOSFree(poc, pocsize);
  416. end
  417. else
  418. begin
  419. {$endif}
  420. if loc_freelists^.oslast = nil then
  421. loc_freelists^.oslast := poc
  422. else
  423. loc_freelists^.oslast^.next := poc;
  424. loc_freelists^.osfirst := poc;
  425. inc(loc_freelists^.oscount);
  426. {$ifdef HAS_SYSOSFREE}
  427. end;
  428. {$endif}
  429. end;
  430. procedure clear_oschunk_on_freelist_fixed_flag(poc: poschunk); inline;
  431. { prevent thinking this os chunk is on the fixed freelists }
  432. begin
  433. pmemchunk_fixed(pointer(poc) + fixedfirstoffset)^.size := 0;
  434. end;
  435. procedure append_to_oslist_var(pmc: pmemchunk_var);
  436. var
  437. poc: poschunk;
  438. begin
  439. // block eligable for freeing
  440. poc := pointer(pmc)-varfirstoffset;
  441. remove_from_list_var(pmc);
  442. clear_oschunk_on_freelist_fixed_flag(poc);
  443. append_to_oslist(poc, 0);
  444. end;
  445. {*****************************************************************************
  446. Split block
  447. *****************************************************************************}
  448. procedure split_block(pcurr: pmemchunk_var; size: ptrint);
  449. var
  450. pcurr_tmp : pmemchunk_var;
  451. sizeleft: ptrint;
  452. begin
  453. sizeleft := (pcurr^.size and sizemask)-size;
  454. if sizeleft>=sizeof(tmemchunk_var) then
  455. begin
  456. pcurr_tmp := pmemchunk_var(pointer(pcurr)+size);
  457. { update prevsize of block to the right }
  458. if (pcurr^.size and lastblockflag) = 0 then
  459. pmemchunk_var(pointer(pcurr)+(pcurr^.size and sizemask))^.prevsize := sizeleft;
  460. { inherit the lastblockflag }
  461. pcurr_tmp^.size := sizeleft or (pcurr^.size and lastblockflag);
  462. pcurr_tmp^.prevsize := size;
  463. pcurr_tmp^.freelists := pcurr^.freelists;
  464. { the block we return is not the last one anymore (there's now a block after it) }
  465. { decrease size of block to new size }
  466. pcurr^.size := size or (pcurr^.size and (not sizemask and not lastblockflag));
  467. { insert the block in the freelist }
  468. append_to_list_var(pcurr_tmp);
  469. end;
  470. end;
  471. {*****************************************************************************
  472. Try concat freerecords
  473. *****************************************************************************}
  474. procedure concat_two_blocks(mc_left, mc_right: pmemchunk_var);
  475. var
  476. mc_tmp : pmemchunk_var;
  477. size_right : ptrint;
  478. begin
  479. // mc_right can't be a fixed size block
  480. if mc_right^.size and fixedsizeflag<>0 then
  481. HandleError(204);
  482. // left block free, concat with right-block
  483. size_right := mc_right^.size and sizemask;
  484. inc(mc_left^.size, size_right);
  485. // if right-block was last block, copy flag
  486. if (mc_right^.size and lastblockflag) <> 0 then
  487. begin
  488. mc_left^.size := mc_left^.size or lastblockflag;
  489. end
  490. else
  491. begin
  492. // there is a block to the right of the right-block, adjust it's prevsize
  493. mc_tmp := pmemchunk_var(pointer(mc_right)+size_right);
  494. mc_tmp^.prevsize := mc_left^.size and sizemask;
  495. end;
  496. // remove right-block from doubly linked list
  497. remove_from_list_var(mc_right);
  498. end;
  499. procedure try_concat_free_chunk_forward(mc: pmemchunk_var);
  500. var
  501. mc_tmp : pmemchunk_var;
  502. begin
  503. { try concat forward }
  504. if (mc^.size and lastblockflag) = 0 then
  505. begin
  506. mc_tmp := pmemchunk_var(pointer(mc)+(mc^.size and sizemask));
  507. if (mc_tmp^.size and usedflag) = 0 then
  508. begin
  509. // next block free: concat
  510. concat_two_blocks(mc, mc_tmp);
  511. end;
  512. end;
  513. end;
  514. function try_concat_free_chunk(mc: pmemchunk_var): pmemchunk_var;
  515. var
  516. mc_tmp : pmemchunk_var;
  517. begin
  518. try_concat_free_chunk_forward(mc);
  519. { try concat backward }
  520. if (mc^.size and firstblockflag) = 0 then
  521. begin
  522. mc_tmp := pmemchunk_var(pointer(mc)-mc^.prevsize);
  523. if (mc_tmp^.size and usedflag) = 0 then
  524. begin
  525. // prior block free: concat
  526. concat_two_blocks(mc_tmp, mc);
  527. mc := mc_tmp;
  528. end;
  529. end;
  530. result := mc;
  531. end;
  532. function check_concat_free_chunk_forward(mc: pmemchunk_var;reqsize:ptrint):boolean;
  533. var
  534. mc_tmp : pmemchunk_var;
  535. freesize : ptrint;
  536. begin
  537. check_concat_free_chunk_forward:=false;
  538. freesize:=0;
  539. mc_tmp:=mc;
  540. repeat
  541. inc(freesize,mc_tmp^.size and sizemask);
  542. if freesize>=reqsize then
  543. begin
  544. check_concat_free_chunk_forward:=true;
  545. exit;
  546. end;
  547. if (mc_tmp^.size and lastblockflag) <> 0 then
  548. break;
  549. mc_tmp := pmemchunk_var(pointer(mc_tmp)+(mc_tmp^.size and sizemask));
  550. if (mc_tmp^.size and usedflag) <> 0 then
  551. break;
  552. until false;
  553. end;
  554. {*****************************************************************************
  555. Grow Heap
  556. *****************************************************************************}
  557. function alloc_oschunk(loc_freelists: pfreelists; chunkindex, size: ptrint): pointer;
  558. var
  559. pmc,
  560. pmc_next : pmemchunk_fixed;
  561. pmcv : pmemchunk_var;
  562. poc : poschunk;
  563. prev_poc : poschunk;
  564. minsize,
  565. maxsize,
  566. i : ptrint;
  567. chunksize : ptrint;
  568. pocsize : ptrint;
  569. status : pfpcheapstatus;
  570. begin
  571. { increase size by size needed for os block header }
  572. minsize := size + varfirstoffset;
  573. { for fixed size chunks we keep offset from os chunk to mem chunk in
  574. upper bits, so maximum os chunk size is 64K on 32bit for fixed size }
  575. if chunkindex<>0 then
  576. maxsize := 1 shl (32-fixedoffsetshift)
  577. else
  578. maxsize := high(ptrint);
  579. { blocks available in freelist? }
  580. poc := loc_freelists^.osfirst;
  581. prev_poc := nil;
  582. while poc <> nil do
  583. begin
  584. if (poc^.size and ocrecycleflag) <> 0 then
  585. begin
  586. { oops! we recycled this chunk; remove it from list }
  587. poc^.size := poc^.size and not ocrecycleflag;
  588. poc := poc^.next;
  589. if prev_poc = nil then
  590. loc_freelists^.osfirst := poc
  591. else
  592. prev_poc^.next := poc;
  593. if poc = nil then
  594. loc_freelists^.oslast := nil;
  595. continue;
  596. end;
  597. pocsize := poc^.size and sizemask;
  598. if (pocsize >= minsize) and
  599. (pocsize <= maxsize) then
  600. begin
  601. size := pocsize;
  602. if prev_poc = nil then
  603. loc_freelists^.osfirst := poc^.next
  604. else
  605. prev_poc^.next := poc^.next;
  606. if poc^.next = nil then
  607. loc_freelists^.oslast := nil;
  608. dec(loc_freelists^.oscount);
  609. pmc := pmemchunk_fixed(pointer(poc)+fixedfirstoffset);
  610. if pmc^.size <> 0 then
  611. remove_all_from_list_fixed(pmc^.size and fixedsizemask, poc);
  612. break;
  613. end;
  614. prev_poc := poc;
  615. poc := poc^.next;
  616. end;
  617. if poc = nil then
  618. begin
  619. {$ifdef DUMPGROW}
  620. writeln('growheap(',size,') allocating ',(size+sizeof(toschunk)+$ffff) and not $ffff);
  621. DumpBlocks(loc_freelists);
  622. {$endif}
  623. { allocate by 64K size }
  624. size := (size+varfirstoffset+$ffff) and not $ffff;
  625. { allocate smaller blocks for fixed-size chunks }
  626. if chunkindex<>0 then
  627. begin
  628. poc := SysOSAlloc(GrowHeapSizeSmall);
  629. if poc<>nil then
  630. size := GrowHeapSizeSmall;
  631. end
  632. { first try 256K (default) }
  633. else if size<=GrowHeapSize1 then
  634. begin
  635. poc := SysOSAlloc(GrowHeapSize1);
  636. if poc<>nil then
  637. size := GrowHeapSize1;
  638. end
  639. { second try 1024K (default) }
  640. else if size<=GrowHeapSize2 then
  641. begin
  642. poc := SysOSAlloc(GrowHeapSize2);
  643. if poc<>nil then
  644. size := GrowHeapSize2;
  645. end
  646. { else allocate the needed bytes }
  647. else
  648. poc := SysOSAlloc(size);
  649. { try again }
  650. if poc=nil then
  651. begin
  652. poc := SysOSAlloc(size);
  653. if poc=nil then
  654. begin
  655. if ReturnNilIfGrowHeapFails then
  656. begin
  657. result := nil;
  658. exit
  659. end
  660. else
  661. HandleError(203);
  662. end;
  663. end;
  664. { prevent thinking this os chunk is on some freelist }
  665. clear_oschunk_on_freelist_fixed_flag(poc);
  666. poc^.next := nil;
  667. poc^.freelists := loc_freelists;
  668. { set the total new heap size }
  669. status := @loc_freelists^.internal_status;
  670. inc(status^.currheapsize, size);
  671. if status^.currheapsize > status^.maxheapsize then
  672. status^.maxheapsize := status^.currheapsize;
  673. end;
  674. { initialize os-block }
  675. poc^.used := 0;
  676. poc^.size := size;
  677. if chunkindex<>0 then
  678. begin
  679. { chop os chunk in fixedsize parts,
  680. maximum of $ffff elements are allowed, otherwise
  681. there will be an overflow }
  682. chunksize := chunkindex shl blockshift;
  683. if size-chunksize>maxsize then
  684. HandleError(204);
  685. { we need to align the user pointers to 8 byte at least for
  686. mmx/sse and doubles on sparc, align to 16 bytes }
  687. i := fixedfirstoffset;
  688. result := pointer(poc) + i;
  689. pmc := pmemchunk_fixed(result);
  690. pmc^.prev_fixed := nil;
  691. repeat
  692. pmc^.size := fixedsizeflag or chunksize or (i shl fixedoffsetshift);
  693. inc(i, chunksize);
  694. if i > size - chunksize then break;
  695. pmc_next := pmemchunk_fixed(pointer(pmc)+chunksize);
  696. pmc^.next_fixed := pmc_next;
  697. pmc_next^.prev_fixed := pmc;
  698. pmc := pmc_next;
  699. until false;
  700. pmc_next := loc_freelists^.fixedlists[chunkindex];
  701. pmc^.next_fixed := pmc_next;
  702. if pmc_next<>nil then
  703. pmc_next^.prev_fixed := pmc;
  704. loc_freelists^.fixedlists[chunkindex] := pmemchunk_fixed(result);
  705. end
  706. else
  707. begin
  708. { we need to align the user pointers to 8 byte at least for
  709. mmx/sse and doubles on sparc, align to 16 bytes }
  710. result := pointer(poc)+varfirstoffset;
  711. pmcv := pmemchunk_var(result);
  712. pmcv^.size := ((size-varfirstoffset) and sizemask) or (firstblockflag or lastblockflag);
  713. pmcv^.prevsize := 0;
  714. pmcv^.freelists := loc_freelists;
  715. append_to_list_var(pmcv);
  716. end;
  717. end;
  718. procedure update_heapused(var status: tfpcheapstatus; var size: ptrint);
  719. begin
  720. inc(status.currheapused, size);
  721. if status.currheapused > status.maxheapused then
  722. begin
  723. status.maxheapused := status.currheapused;
  724. {$ifdef DUMP_MEM_USAGE}
  725. maxsizeusage := sizeusage;
  726. {$endif}
  727. end;
  728. end;
  729. {*****************************************************************************
  730. SysGetMem
  731. *****************************************************************************}
  732. function finish_waitfixedlist(loc_freelists: pfreelists): boolean; forward;
  733. procedure finish_waitvarlist(loc_freelists: pfreelists); forward;
  734. function SysGetMem_Fixed(chunksize: ptrint): pointer;
  735. var
  736. pmc, pmc_next: pmemchunk_fixed;
  737. poc: poschunk;
  738. chunkindex: ptrint;
  739. loc_freelists: pfreelists;
  740. begin
  741. { try to find a block in one of the freelists per size }
  742. chunkindex := chunksize shr blockshift;
  743. loc_freelists := @freelists;
  744. pmc := loc_freelists^.fixedlists[chunkindex];
  745. { no free blocks ? }
  746. if assigned(pmc) then
  747. begin
  748. { remove oschunk from free list in case we recycle it }
  749. poc := poschunk(pointer(pmc) - (pmc^.size shr fixedoffsetshift));
  750. if poc^.used = 0 then
  751. begin
  752. poc^.size := poc^.size or ocrecycleflag;
  753. dec(loc_freelists^.oscount);
  754. end;
  755. end
  756. else if finish_waitfixedlist(loc_freelists) then
  757. { freed some to-be freed chunks, retry allocation }
  758. exit(SysGetMem_Fixed(chunksize))
  759. else
  760. begin
  761. pmc := alloc_oschunk(loc_freelists, chunkindex, chunksize);
  762. if not assigned(pmc) then
  763. exit(nil);
  764. poc := poschunk(pointer(pmc)-fixedfirstoffset);
  765. end;
  766. { get a pointer to the block we should return }
  767. result := pointer(pmc)+sizeof(tmemchunk_fixed_hdr);
  768. { update freelist }
  769. pmc_next := pmc^.next_fixed;
  770. loc_freelists^.fixedlists[chunkindex] := pmc_next;
  771. if assigned(pmc_next) then
  772. pmc_next^.prev_fixed := nil;
  773. inc(poc^.used);
  774. { statistics }
  775. with loc_freelists^.internal_status do
  776. begin
  777. inc(currheapused, chunksize);
  778. if currheapused > maxheapused then
  779. begin
  780. maxheapused := currheapused;
  781. {$ifdef DUMP_MEM_USAGE}
  782. maxsizeusage := sizeusage;
  783. {$endif}
  784. end;
  785. end;
  786. end;
  787. function SysGetMem_Var(size: ptrint): pointer;
  788. var
  789. pcurr : pmemchunk_var;
  790. pbest : pmemchunk_var;
  791. loc_freelists : pfreelists;
  792. iter : longint;
  793. begin
  794. result:=nil;
  795. { free pending items }
  796. loc_freelists := @freelists;
  797. finish_waitvarlist(loc_freelists);
  798. pbest := nil;
  799. pcurr := loc_freelists^.varlist;
  800. iter := high(longint);
  801. while assigned(pcurr) and (iter>0) do
  802. begin
  803. if (pcurr^.size>size) then
  804. begin
  805. if not assigned(pbest) or (pcurr^.size<pbest^.size) then
  806. begin
  807. pbest := pcurr;
  808. if pcurr^.size = size then
  809. break;
  810. end;
  811. iter := matcheffort;
  812. end;
  813. pcurr := pcurr^.next_var;
  814. dec(iter);
  815. end;
  816. pcurr := pbest;
  817. if not assigned(pcurr) then
  818. begin
  819. // all os-chunks full, allocate a new one
  820. pcurr := alloc_oschunk(loc_freelists, 0, size);
  821. if not assigned(pcurr) then
  822. exit;
  823. end;
  824. { get pointer of the block we should return }
  825. result := pointer(pcurr)+sizeof(tmemchunk_var_hdr);
  826. { remove the current block from the freelist }
  827. remove_from_list_var(pcurr);
  828. { create the left over freelist block, if at least 16 bytes are free }
  829. split_block(pcurr, size);
  830. { flag block as used }
  831. pcurr^.size := pcurr^.size or usedflag;
  832. pcurr^.freelists := loc_freelists;
  833. { statistics }
  834. with loc_freelists^.internal_status do
  835. begin
  836. inc(currheapused, size);
  837. if currheapused > maxheapused then
  838. begin
  839. maxheapused := currheapused;
  840. {$ifdef DUMP_MEM_USAGE}
  841. maxsizeusage := sizeusage;
  842. {$endif}
  843. end;
  844. end;
  845. end;
  846. function SysGetMem(size : ptrint):pointer;
  847. begin
  848. { Something to allocate ? }
  849. if size<=0 then
  850. begin
  851. { give an error for < 0 }
  852. if size<0 then
  853. HandleError(204);
  854. { we always need to allocate something, using heapend is not possible,
  855. because heappend can be changed by growheap (PFV) }
  856. size := 1;
  857. end;
  858. { calc to multiple of 16 after adding the needed bytes for memchunk header }
  859. if size <= (maxblocksize - sizeof(tmemchunk_fixed_hdr)) then
  860. begin
  861. size := (size+(sizeof(tmemchunk_fixed_hdr)+(blocksize-1))) and fixedsizemask;
  862. result := sysgetmem_fixed(size);
  863. end
  864. else
  865. begin
  866. size := (size+(sizeof(tmemchunk_var_hdr)+(blocksize-1))) and sizemask;
  867. result := sysgetmem_var(size);
  868. end;
  869. {$ifdef DUMP_MEM_USAGE}
  870. size := sysmemsize(result);
  871. if size > sizeusagesize then
  872. inc(sizeusage[sizeusageindex])
  873. else
  874. inc(sizeusage[size shr sizeusageshift]);
  875. {$endif}
  876. end;
  877. {*****************************************************************************
  878. SysFreeMem
  879. *****************************************************************************}
  880. procedure waitfree_fixed(pmc: pmemchunk_fixed; loc_freelists: pfreelists);
  881. begin
  882. entercriticalsection(loc_freelists^.lockfixed);
  883. pmc^.next_fixed := loc_freelists^.waitfixed;
  884. loc_freelists^.waitfixed := pmc;
  885. leavecriticalsection(loc_freelists^.lockfixed);
  886. end;
  887. procedure waitfree_var(pmcv: pmemchunk_var; loc_freelists: pfreelists);
  888. begin
  889. entercriticalsection(loc_freelists^.lockvar);
  890. pmcv^.next_var := loc_freelists^.waitvar;
  891. loc_freelists^.waitvar := pmcv;
  892. leavecriticalsection(loc_freelists^.lockvar);
  893. end;
  894. function SysFreeMem_Fixed(pmc: pmemchunk_fixed): ptrint;
  895. var
  896. chunkindex,
  897. chunksize: ptrint;
  898. poc: poschunk;
  899. pmc_next: pmemchunk_fixed;
  900. loc_freelists: pfreelists;
  901. begin
  902. poc := poschunk(pointer(pmc)-(pmc^.size shr fixedoffsetshift));
  903. chunksize := pmc^.size and fixedsizemask;
  904. loc_freelists := @freelists;
  905. if loc_freelists <> poc^.freelists then
  906. begin
  907. if poc^.freelists = main_orig_freelists then
  908. poc^.freelists := main_relo_freelists;
  909. if loc_freelists <> poc^.freelists then
  910. begin
  911. { deallocated in wrong thread! add to to-be-freed list of correct thread }
  912. waitfree_fixed(pmc, poc^.freelists);
  913. exit(chunksize);
  914. end;
  915. end;
  916. dec(loc_freelists^.internal_status.currheapused, chunksize);
  917. { insert the block in it's freelist }
  918. chunkindex := chunksize shr blockshift;
  919. pmc_next := loc_freelists^.fixedlists[chunkindex];
  920. pmc^.prev_fixed := nil;
  921. pmc^.next_fixed := pmc_next;
  922. if assigned(pmc_next) then
  923. pmc_next^.prev_fixed := pmc;
  924. loc_freelists^.fixedlists[chunkindex] := pmc;
  925. { decrease used blocks count }
  926. dec(poc^.used);
  927. if poc^.used <= 0 then
  928. begin
  929. { decrease used blocks count }
  930. if poc^.used=-1 then
  931. HandleError(204);
  932. { osblock can be freed? }
  933. append_to_oslist(poc, chunksize);
  934. end;
  935. result := chunksize;
  936. end;
  937. function SysFreeMem_Var(pmcv: pmemchunk_var): ptrint;
  938. var
  939. chunksize: ptrint;
  940. loc_freelists: pfreelists;
  941. begin
  942. chunksize := pmcv^.size and sizemask;
  943. loc_freelists := @freelists;
  944. if loc_freelists <> pmcv^.freelists then
  945. begin
  946. if pmcv^.freelists = main_orig_freelists then
  947. pmcv^.freelists := main_relo_freelists;
  948. if loc_freelists <> pmcv^.freelists then
  949. begin
  950. { deallocated in wrong thread! add to to-be-freed list of correct thread }
  951. waitfree_var(pmcv, pmcv^.freelists);
  952. exit(chunksize);
  953. end;
  954. end;
  955. dec(loc_freelists^.internal_status.currheapused, chunksize);
  956. { insert the block in it's freelist }
  957. pmcv^.size := pmcv^.size and (not usedflag);
  958. append_to_list_var(pmcv);
  959. pmcv := try_concat_free_chunk(pmcv);
  960. if (pmcv^.size and (firstblockflag or lastblockflag)) = (firstblockflag or lastblockflag) then
  961. append_to_oslist_var(pmcv);
  962. result := chunksize;
  963. end;
  964. function SysFreeMem(p: pointer): ptrint;
  965. var
  966. pmc: pmemchunk_fixed;
  967. {$ifdef DUMP_MEM_USAGE}
  968. size: sizeint;
  969. {$endif}
  970. begin
  971. if p=nil then
  972. begin
  973. result:=0;
  974. exit;
  975. end;
  976. {$ifdef DUMP_MEM_USAGE}
  977. size := sysmemsize(p);
  978. if size > sizeusagesize then
  979. dec(sizeusage[sizeusageindex])
  980. else
  981. dec(sizeusage[size shr sizeusageshift]);
  982. {$endif}
  983. pmc := pmemchunk_fixed(p-sizeof(tmemchunk_fixed_hdr));
  984. { check if this is a fixed- or var-sized chunk }
  985. if (pmc^.size and fixedsizeflag) = 0 then
  986. result := sysfreemem_var(pmemchunk_var(p-sizeof(tmemchunk_var_hdr)))
  987. else
  988. result := sysfreemem_fixed(pmc);
  989. end;
  990. function finish_waitfixedlist(loc_freelists: pfreelists): boolean;
  991. { free to-be-freed chunks, return whether we freed anything }
  992. var
  993. pmc: pmemchunk_fixed;
  994. begin
  995. if loc_freelists^.waitfixed = nil then
  996. exit(false);
  997. entercriticalsection(loc_freelists^.lockfixed);
  998. while loc_freelists^.waitfixed <> nil do
  999. begin
  1000. { keep next_fixed, might be destroyed }
  1001. pmc := loc_freelists^.waitfixed;
  1002. loc_freelists^.waitfixed := pmc^.next_fixed;
  1003. SysFreeMem_Fixed(pmc);
  1004. end;
  1005. leavecriticalsection(loc_freelists^.lockfixed);
  1006. result := true;
  1007. end;
  1008. procedure finish_waitvarlist(loc_freelists: pfreelists);
  1009. { free to-be-freed chunks, return whether we freed anything }
  1010. var
  1011. pmcv: pmemchunk_var;
  1012. begin
  1013. loc_freelists := @freelists;
  1014. if loc_freelists^.waitvar = nil then
  1015. exit;
  1016. entercriticalsection(loc_freelists^.lockvar);
  1017. while loc_freelists^.waitvar <> nil do
  1018. begin
  1019. { keep next_var, might be destroyed }
  1020. pmcv := loc_freelists^.waitvar;
  1021. loc_freelists^.waitvar := pmcv^.next_var;
  1022. SysFreeMem_Var(pmcv);
  1023. end;
  1024. leavecriticalsection(loc_freelists^.lockvar);
  1025. end;
  1026. {*****************************************************************************
  1027. SysFreeMemSize
  1028. *****************************************************************************}
  1029. Function SysFreeMemSize(p: pointer; size: ptrint):ptrint;
  1030. begin
  1031. if size<=0 then
  1032. begin
  1033. if size<0 then
  1034. HandleError(204);
  1035. exit(0);
  1036. end;
  1037. { can't free partial blocks, ignore size }
  1038. result := SysFreeMem(p);
  1039. end;
  1040. {*****************************************************************************
  1041. SysMemSize
  1042. *****************************************************************************}
  1043. function SysMemSize(p: pointer): ptrint;
  1044. begin
  1045. result := pmemchunk_fixed(pointer(p)-sizeof(tmemchunk_fixed_hdr))^.size;
  1046. if (result and fixedsizeflag) = 0 then
  1047. begin
  1048. result := result and sizemask;
  1049. dec(result, sizeof(tmemchunk_var_hdr));
  1050. end
  1051. else
  1052. begin
  1053. result := result and fixedsizemask;
  1054. dec(result, sizeof(tmemchunk_fixed_hdr));
  1055. end;
  1056. end;
  1057. {*****************************************************************************
  1058. SysAllocMem
  1059. *****************************************************************************}
  1060. function SysAllocMem(size: ptrint): pointer;
  1061. begin
  1062. result := MemoryManager.GetMem(size);
  1063. if result<>nil then
  1064. FillChar(result^,MemoryManager.MemSize(result),0);
  1065. end;
  1066. {*****************************************************************************
  1067. SysResizeMem
  1068. *****************************************************************************}
  1069. function SysTryResizeMem(var p: pointer; size: ptrint): boolean;
  1070. var
  1071. chunksize,
  1072. oldsize,
  1073. currsize : ptrint;
  1074. pcurr : pmemchunk_var;
  1075. begin
  1076. SysTryResizeMem := false;
  1077. { fix p to point to the heaprecord }
  1078. chunksize := pmemchunk_fixed(p-sizeof(tmemchunk_fixed_hdr))^.size;
  1079. { handle fixed memchuncks separate. Only allow resizes when the
  1080. new size fits in the same block }
  1081. if (chunksize and fixedsizeflag) <> 0 then
  1082. begin
  1083. currsize := chunksize and fixedsizemask;
  1084. { 1. Resizing to smaller sizes will never allocate a new block. We just keep the current block. This
  1085. is needed for the expectations that resizing to a small block will not move the contents of
  1086. a memory block
  1087. 2. For resizing to greater size first check if the size fits in the fixed block range to prevent
  1088. "truncating" the size by the fixedsizemask }
  1089. if ((size <= (maxblocksize - sizeof(tmemchunk_fixed_hdr))) and
  1090. ((size+sizeof(tmemchunk_fixed_hdr)+(blocksize-1)) and sizemask <= currsize)) then
  1091. begin
  1092. systryresizemem:=true;
  1093. exit;
  1094. end;
  1095. { we need to allocate a new fixed or var memchunck }
  1096. exit;
  1097. end;
  1098. { var memchunck }
  1099. currsize := chunksize and sizemask;
  1100. size := (size+sizeof(tmemchunk_var_hdr)+(blocksize-1)) and sizemask;
  1101. { is the allocated block still correct? }
  1102. if (currsize>=size) and (size>(currsize-blocksize)) then
  1103. begin
  1104. SysTryResizeMem := true;
  1105. exit;
  1106. end;
  1107. { get pointer to block }
  1108. pcurr := pmemchunk_var(pointer(p)-sizeof(tmemchunk_var_hdr));
  1109. oldsize := currsize;
  1110. { do we need to allocate more memory ? }
  1111. if size>currsize then
  1112. begin
  1113. { the size is bigger than the previous size, we need to allocated more mem.
  1114. We first check if the blocks after the current block are free. If not then we
  1115. simply call getmem/freemem to get the new block }
  1116. if check_concat_free_chunk_forward(pcurr,size) then
  1117. repeat
  1118. concat_two_blocks(pcurr,pmemchunk_var(pointer(pcurr)+currsize));
  1119. currsize := pcurr^.size and sizemask;
  1120. until currsize>=size
  1121. else
  1122. exit;
  1123. end;
  1124. { is the size smaller then we can adjust the block to that size and insert
  1125. the other part into the freelist }
  1126. if currsize>size then
  1127. split_block(pcurr, size);
  1128. inc(freelists.internal_status.currheapused, size-oldsize);
  1129. SysTryResizeMem := true;
  1130. end;
  1131. {*****************************************************************************
  1132. SysResizeMem
  1133. *****************************************************************************}
  1134. function SysReAllocMem(var p: pointer; size: ptrint):pointer;
  1135. var
  1136. newsize,
  1137. oldsize,
  1138. minsize : ptrint;
  1139. p2 : pointer;
  1140. begin
  1141. { Free block? }
  1142. if size=0 then
  1143. begin
  1144. if p<>nil then
  1145. begin
  1146. MemoryManager.FreeMem(p);
  1147. p := nil;
  1148. end;
  1149. end
  1150. else
  1151. { Allocate a new block? }
  1152. if p=nil then
  1153. begin
  1154. p := MemoryManager.GetMem(size);
  1155. end
  1156. else
  1157. begin
  1158. { Resize block }
  1159. {$ifdef DUMP_MEM_USAGE}
  1160. oldsize:=SysMemSize(p);
  1161. {$endif}
  1162. if not SysTryResizeMem(p,size) then
  1163. begin
  1164. oldsize:=MemoryManager.MemSize(p);
  1165. { Grow with bigger steps to prevent the need for
  1166. multiple getmem/freemem calls for fixed blocks. It might cost a bit
  1167. of extra memory, but in most cases a reallocmem is done multiple times. }
  1168. if oldsize<maxblocksize then
  1169. begin
  1170. newsize:=oldsize*2+blocksize;
  1171. if size>newsize then
  1172. newsize:=size;
  1173. end
  1174. else
  1175. newsize:=size;
  1176. { calc size of data to move }
  1177. minsize:=oldsize;
  1178. if newsize < minsize then
  1179. minsize := newsize;
  1180. p2 := MemoryManager.GetMem(newsize);
  1181. if p2<>nil then
  1182. Move(p^,p2^,minsize);
  1183. MemoryManager.FreeMem(p);
  1184. p := p2;
  1185. {$ifdef DUMP_MEM_USAGE}
  1186. end else begin
  1187. size := sysmemsize(p);
  1188. if size <> oldsize then
  1189. begin
  1190. if oldsize > sizeusagesize then
  1191. dec(sizeusage[sizeusageindex])
  1192. else if oldsize >= 0 then
  1193. dec(sizeusage[oldsize shr sizeusageshift]);
  1194. if size > sizeusagesize then
  1195. inc(sizeusage[sizeusageindex])
  1196. else if size >= 0 then
  1197. inc(sizeusage[size shr sizeusageshift]);
  1198. end;
  1199. {$endif}
  1200. end;
  1201. end;
  1202. SysReAllocMem := p;
  1203. end;
  1204. {$endif HAS_MEMORYMANAGER}
  1205. {$ifndef HAS_MEMORYMANAGER}
  1206. {*****************************************************************************
  1207. InitHeap
  1208. *****************************************************************************}
  1209. {$if not(defined(gba)) and not(defined(nds))}
  1210. { This function will initialize the Heap manager and need to be called from
  1211. the initialization of the system unit }
  1212. procedure InitHeapThread;
  1213. var
  1214. loc_freelists: pfreelists;
  1215. begin
  1216. loc_freelists := @freelists;
  1217. fillchar(loc_freelists^,sizeof(tfreelists),0);
  1218. initcriticalsection(loc_freelists^.lockfixed);
  1219. initcriticalsection(loc_freelists^.lockvar);
  1220. {$ifdef DUMP_MEM_USAGE}
  1221. fillchar(sizeusage,sizeof(sizeusage),0);
  1222. fillchar(maxsizeusage,sizeof(sizeusage),0);
  1223. {$endif}
  1224. end;
  1225. procedure InitHeap;
  1226. var
  1227. loc_freelists: pfreelists;
  1228. begin
  1229. { we cannot initialize the locks here yet, thread support is
  1230. not loaded yet }
  1231. loc_freelists := @freelists;
  1232. fillchar(loc_freelists^,sizeof(tfreelists),0);
  1233. { main freelist will be copied in memory }
  1234. main_orig_freelists := loc_freelists;
  1235. end;
  1236. {$endif}
  1237. procedure RelocateHeap;
  1238. var
  1239. loc_freelists: pfreelists;
  1240. begin
  1241. { this function should be called in main thread context }
  1242. loc_freelists := @freelists;
  1243. main_relo_freelists := loc_freelists;
  1244. initcriticalsection(loc_freelists^.lockfixed);
  1245. initcriticalsection(loc_freelists^.lockvar);
  1246. if MemoryManager.RelocateHeap <> nil then
  1247. MemoryManager.RelocateHeap();
  1248. end;
  1249. procedure FinalizeHeap;
  1250. var
  1251. poc : poschunk;
  1252. i : longint;
  1253. loc_freelists: pfreelists;
  1254. begin
  1255. loc_freelists := @freelists;
  1256. finish_waitfixedlist(loc_freelists);
  1257. finish_waitvarlist(loc_freelists);
  1258. if main_relo_freelists <> nil then
  1259. begin
  1260. donecriticalsection(loc_freelists^.lockfixed);
  1261. donecriticalsection(loc_freelists^.lockvar);
  1262. end;
  1263. {$ifdef SHOW_MEM_USAGE}
  1264. writeln('Max heap used/size: ', loc_freelists^.internal_status.maxheapused, '/',
  1265. loc_freelists^.internal_status.maxheapsize);
  1266. flush(output);
  1267. {$endif}
  1268. {$ifdef DUMP_MEM_USAGE}
  1269. for i := 0 to sizeusageindex-1 do
  1270. if maxsizeusage[i] <> 0 then
  1271. writeln('size ', i shl sizeusageshift, ' usage ', maxsizeusage[i]);
  1272. writeln('size >', sizeusagesize, ' usage ', maxsizeusage[sizeusageindex]);
  1273. flush(output);
  1274. {$endif}
  1275. {$ifdef HAS_SYSOSFREE}
  1276. while assigned(freelists.osfirst) do
  1277. begin
  1278. poc:=loc_freelists^.osfirst^.next;
  1279. SysOSFree(loc_freelists^.osfirst, loc_freelists^.osfirst^.size and sizemask);
  1280. dec(loc_freelists^.oscount);
  1281. loc_freelists^.osfirst:=poc;
  1282. end;
  1283. loc_freelists^.oslast:=nil;
  1284. {$endif HAS_SYSOSFREE}
  1285. end;
  1286. {$endif HAS_MEMORYMANAGER}