Heaps.Mod 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543
  1. MODULE Heaps; (** AUTHOR "pjm/Luc Bläser/U. Glavitsch (ug)"; PURPOSE "Heap management and garbage collector"; *)
  2. (*
  3. This module contains lots of low-level memory manipulations, which are best
  4. read together with the memory management data structure documentation.
  5. Garbage collector using a marking stack with overflow handling,
  6. References:
  7. Jones, Lins, Garbage Collection, Section 4.2, Algorithm 4.1
  8. Knuth, The Art of Computer Programming, Volume 1, Section 2.3.5, Algorithm C
  9. *)
  10. IMPORT SYSTEM, Trace, Machine;
  11. CONST
  12. DebugValue = LONGINT(0DEADDEADH); (* set non-0 to clear free storage to this value *)
  13. Stats* = TRUE; (* maintain statistical counters *)
  14. AddressSize = SIZEOF(ADDRESS);
  15. MaxTries = 16; (* max number of times to try and allocate memory, before trapping *)
  16. Unmarked = -1; (* mark value of free blocks *)
  17. BlockSize* = 32; (* power of two, <= 32 for RegisterCandidates *)
  18. ArrayAlignment = 8; (* first array element of ArrayBlock and first data element of SystemBlock must be aligned to 0 MOD ArrayAlignment *)
  19. BlockHeaderSize* = 2 * AddressSize;
  20. HeapBlockOffset* = - 2 * AddressSize;
  21. TypeDescOffset* = - AddressSize;
  22. MaxCandidates = 1024;
  23. ProtTypeBit* = 31; (** flags in TypeDesc, RoundUp(log2(MaxTags)) low bits reserved for extLevel *)
  24. FlagsOfs = AddressSize * 3; (* flags offset in TypeDesc *)
  25. ModOfs* = AddressSize * 4; (* moduleAdr offset in TypeDesc *)
  26. TypeNameOfs = AddressSize * 5; (* type name offset in TypeDesc *)
  27. ModNameOfs = AddressSize * 2; (* module name offset in ModuleDesc *)
  28. MinPtrOfs = -40000000H; (* sentinel offset for ptrOfs *)
  29. MethodEndMarker* = MinPtrOfs; (* marks the end of the method addresses, used in Info.ModuleDetails *)
  30. NilVal* = 0;
  31. NumPriorities* = 6;
  32. HeuristicStackInspectionGC* = 0;
  33. MetaDataForStackGC* = 1;
  34. TYPE
  35. RootObject* = OBJECT (* ref. Linker0 *)
  36. VAR nextRoot: RootObject; (* for linking root objects during GC *)
  37. PROCEDURE FindRoots*; (** abstract *)
  38. BEGIN HALT(301) END FindRoots;
  39. END RootObject;
  40. ProcessLink* = OBJECT (RootObject)
  41. VAR next*, prev*: ProcessLink
  42. END ProcessLink;
  43. ProcessQueue* = RECORD
  44. head*, tail*: ProcessLink
  45. END;
  46. Finalizer* = PROCEDURE {DELEGATE} (obj: ANY);
  47. FinalizerNode* = POINTER TO RECORD
  48. objWeak* {UNTRACED}: ANY; (* weak reference to checked object *)
  49. nextFin: FinalizerNode; (* in finalization list *)
  50. objStrong*: ANY; (* strong reference to object to be finalized *)
  51. finalizer* {UNTRACED} : Finalizer;(* finalizer, if any. Untraced for the case that a finalizer points to objWeak *)
  52. finalizerStrong: Finalizer; (* strong reference to the object that is referenced by the finalizer, if any *)
  53. END;
  54. HeapBlock* = POINTER TO HeapBlockDesc; (* base object of all heap blocks *)
  55. HeapBlockU = POINTER {UNSAFE} TO HeapBlockDesc; (* base object of all heap blocks *)
  56. HeapBlockDesc* = RECORD
  57. heapBlock {FICTIVE =HeapBlockOffset}: ADDRESS;
  58. typeDesc {FICTIVE =TypeDescOffset}: POINTER {UNSAFE} TO StaticTypeDesc;
  59. mark: LONGINT;
  60. dataAdr-: ADDRESS;
  61. size-: SIZE;
  62. nextMark {UNTRACED}: HeapBlock;
  63. END;
  64. FreeBlock* = POINTER TO FreeBlockDesc;
  65. FreeBlockU = POINTER {UNSAFE} TO FreeBlockDesc;
  66. FreeBlockDesc* = RECORD (HeapBlockDesc)
  67. next: FreeBlock;
  68. END;
  69. SystemBlock* = POINTER TO SystemBlockDesc;
  70. SystemBlockDesc = RECORD (HeapBlockDesc)
  71. END;
  72. RecordBlock* = POINTER TO RecordBlockDesc;
  73. RecordBlockU = POINTER {UNSAFE} TO RecordBlockDesc;
  74. RecordBlockDesc = RECORD (HeapBlockDesc)
  75. END;
  76. ProtRecBlock* = POINTER TO ProtRecBlockDesc;
  77. ProtRecBlockU = POINTER {UNSAFE} TO ProtRecBlockDesc;
  78. ProtRecBlockDesc* = RECORD (RecordBlockDesc)
  79. count*: LONGINT;
  80. locked*: BOOLEAN;
  81. awaitingLock*, awaitingCond*: ProcessQueue;
  82. lockedBy*: ANY;
  83. waitingPriorities*: ARRAY NumPriorities OF LONGINT;
  84. lock*: ANY; (* generic implementation slot -- used by LinuxAos *)
  85. END;
  86. ArrayBlock* = POINTER TO ArrayBlockDesc;
  87. ArrayBlockU = POINTER {UNSAFE} TO ArrayBlockDesc;
  88. ArrayBlockDesc = RECORD (HeapBlockDesc)
  89. END;
  90. TypeInfo*= POINTER{UNSAFE} TO TypeInfoDesc;
  91. TypeInfoDesc = RECORD
  92. descSize: LONGINT;
  93. sentinel: LONGINT; (* = MPO-4 *)
  94. tag: ADDRESS; (* pointer to static type descriptor, only used by linker and loader *)
  95. flags: SET;
  96. mod: ADDRESS; (* module *)
  97. name*: ARRAY 32 OF CHAR;
  98. END;
  99. StaticTypeBlock*= POINTER TO StaticTypeDesc;
  100. StaticTypeBlockU= POINTER {UNSAFE} TO StaticTypeDesc;
  101. StaticTypeDesc = RECORD
  102. info {FICTIVE =TypeDescOffset}: TypeInfo;
  103. recSize: SIZE;
  104. pointerOffsets* {UNTRACED}: PointerOffsets;
  105. END;
  106. PointerOffsets = POINTER TO ARRAY OF SIZE;
  107. Block*= POINTER {UNSAFE} TO RECORD
  108. heapBlock {FICTIVE =HeapBlockOffset}: HeapBlock;
  109. typeBlock {FICTIVE =TypeDescOffset}: StaticTypeBlock;
  110. END;
  111. DataBlockU = POINTER {UNSAFE} TO DataBlockDesc;
  112. DataBlockDesc*= RECORD
  113. heapBlock {FICTIVE =HeapBlockOffset}: POINTER {UNSAFE} TO HeapBlockDesc;
  114. typeDesc {FICTIVE =TypeDescOffset}: POINTER {UNSAFE} TO StaticTypeDesc;
  115. END;
  116. ArrayDataBlockU = POINTER {UNSAFE} TO ArrayDataBlockDesc;
  117. ArrayDataBlockDesc*= RECORD (DataBlockDesc)
  118. numElems: SIZE;
  119. current: ADDRESS; (* unused *)
  120. first: ADDRESS;
  121. END;
  122. (*StackBlock = POINTER{UNSAFE} TO StackBlockDesc;
  123. StackBlockDesc= RECORD
  124. link: StackBlock;
  125. pc: ADDRESS;
  126. END;
  127. *)
  128. (* a single pointer -- required as base type TD for array of pointer
  129. Don't rename this. Compiler refers to this TD by name
  130. *)
  131. AnyPtr = RECORD a: ANY END;
  132. TYPE
  133. GCStatus* = OBJECT
  134. (* the following procedures are overridden in Objects.GCStatusExt. The reason is that shared objects can only be implemented in modules Objects or higher *)
  135. PROCEDURE SetgcOngoing*(value: BOOLEAN);
  136. BEGIN
  137. HALT(2000);
  138. END SetgcOngoing;
  139. PROCEDURE GetgcOngoing*(): BOOLEAN;
  140. BEGIN
  141. HALT(2001); RETURN FALSE
  142. END GetgcOngoing;
  143. PROCEDURE WaitForGCEnd*;
  144. BEGIN
  145. HALT(2002)
  146. END WaitForGCEnd;
  147. END GCStatus;
  148. CONST
  149. MaxFreeLists = 20;
  150. FreeListBarrier = 7;
  151. TYPE
  152. FreeList= RECORD minSize: SIZE; first {UNTRACED}, last{UNTRACED}: FreeBlock END;
  153. FreeLists = ARRAY MaxFreeLists+1 OF FreeList;
  154. MarkList = RECORD first{UNTRACED}, last{UNTRACED}: HeapBlock END;
  155. VAR
  156. markList: MarkList;
  157. freeLists: FreeLists;
  158. GC*: PROCEDURE; (** activate the garbage collector *)
  159. initBlock {UNTRACED}: ANY; (* anchor for init calls *)
  160. currentMarkValue: LONGINT; (* all objects that have this value in their mark field are still used - initial value filled in by linker *)
  161. sweepMarkValue: LONGINT; (* most recent mark value *)
  162. sweepBlockAdr: ADDRESS; (* where to resume sweeping *)
  163. sweepMemBlock {UNTRACED}: Machine.MemoryBlock; (* where to resume sweeping *)
  164. candidates: ARRAY MaxCandidates OF ADDRESS; (* procedure stack pointer candidates *)
  165. numCandidates: LONGINT;
  166. rootList {UNTRACED}: RootObject; (* list of root objects during GC - tracing does not harm but is unnecessary *)
  167. realtimeList {UNTRACED}: HeapBlock; (* list of realtime objects - tracing does not harm but is unnecessary *)
  168. newSum: SIZE;
  169. checkRoot: FinalizerNode; (* list of checked objects (contains weak references to the checked objects) *)
  170. finalizeRoot: FinalizerNode; (* objects scheduled for finalization (contains references to scheduled objects) *)
  171. freeBlockTag, systemBlockTag, recordBlockTag, protRecBlockTag, arrayBlockTag: ADDRESS; (* same values of type ADDRESS *)
  172. (** Statistics. Will only be maintained if Stats = TRUE *)
  173. (** Memory allocation statistics *)
  174. Nnew- : LONGINT; (** Number of times NewBlock has been called since system startup *)
  175. NnewBytes- : HUGEINT; (** Number of bytes allocated by NewBlock since system startup *)
  176. (** Garbage collection statistics *)
  177. Ngc- : LONGINT; (** Number of GC cycles since system startup *)
  178. (** Statistics considering the last GC cyle *)
  179. Nmark-, Nmarked-, NfinalizeAlive-, NfinalizeDead-: LONGINT;
  180. NgcCyclesMark-, NgcCyclesLastRun-, NgcCyclesMax-, NgcCyclesAllRuns- : HUGEINT;
  181. NgcSweepTime-, NgcSweepMax-: HUGEINT;
  182. gcStatus*: GCStatus;
  183. GCType*: LONGINT;
  184. freeBlockFound-, freeBlockNotFound-: LONGINT;
  185. EnableFreeLists, EnableReturnBlocks, trace-: BOOLEAN;
  186. allocationLogger-: PROCEDURE(p: ANY);
  187. (* for low level debugging of allocation -- beware: errors or traps in allocation logger can produce catastrophy - loggers may not allocate memory *)
  188. PROCEDURE SetAllocationLogger*(a: PROCEDURE (p:ANY));
  189. BEGIN
  190. allocationLogger := a
  191. END SetAllocationLogger;
  192. (* check validity of p *)
  193. PROCEDURE CheckPointer(p: ADDRESS): BOOLEAN;
  194. VAR ret: BOOLEAN; heapBlockAdr, tdAdr: ADDRESS;
  195. BEGIN
  196. ret := FALSE;
  197. IF Machine.ValidHeapAddress(p+HeapBlockOffset)THEN
  198. SYSTEM.GET(p + HeapBlockOffset, heapBlockAdr);
  199. IF Machine.ValidHeapAddress(heapBlockAdr + TypeDescOffset) THEN
  200. SYSTEM.GET(heapBlockAdr + TypeDescOffset, tdAdr);
  201. IF (tdAdr = systemBlockTag) OR (tdAdr = recordBlockTag) OR (tdAdr = protRecBlockTag) OR (tdAdr = arrayBlockTag) THEN
  202. ret := TRUE
  203. END
  204. END
  205. END;
  206. RETURN ret
  207. END CheckPointer;
  208. PROCEDURE AppendToMarkList(heapBlock: HeapBlock);
  209. BEGIN
  210. IF markList.first = NIL THEN
  211. markList.first := heapBlock
  212. ELSE
  213. markList.last.nextMark := heapBlock
  214. END;
  215. markList.last := heapBlock;
  216. heapBlock.nextMark := NIL; (* sanity of the list *)
  217. END AppendToMarkList;
  218. PROCEDURE ExtractFromMarkList(): HeapBlock;
  219. VAR heapBlock: HeapBlock;
  220. BEGIN
  221. heapBlock := markList.first;
  222. IF heapBlock # NIL THEN
  223. markList.first := heapBlock.nextMark;
  224. (* by the construction of AppendToMarkList, it is not necessary to update the last pointer *)
  225. END;
  226. RETURN heapBlock;
  227. END ExtractFromMarkList;
  228. PROCEDURE Inspect(block {UNTRACED}: ANY);
  229. VAR
  230. heapBlock {UNTRACED}: HeapBlock;
  231. rootObj{UNTRACED}: RootObject;
  232. blockMeta : Block;
  233. BEGIN
  234. (* ug: check for validity of block is necessary since users may assign values to pointer variables that are not real heap blocks, e.g. by using SYSTEM.VAL or ADDRESSOF *)
  235. IF (block = NIL) OR ~CheckPointer(block) THEN RETURN END;
  236. blockMeta := block;
  237. heapBlock := blockMeta.heapBlock;
  238. IF (heapBlock = NIL) OR (heapBlock.mark >= currentMarkValue) THEN RETURN END;
  239. heapBlock.mark := currentMarkValue;
  240. IF Stats THEN INC(Nmarked) END;
  241. IF (heapBlock IS RecordBlock) OR (heapBlock IS ProtRecBlock) OR (heapBlock IS ArrayBlock) THEN
  242. IF block IS RootObject THEN
  243. rootObj := block(RootObject);
  244. rootObj.nextRoot := rootList; rootList := rootObj; (* link root list *)
  245. END;
  246. IF (LEN(blockMeta.typeBlock.pointerOffsets) > 0) OR (heapBlock IS ProtRecBlock) THEN (* not atomic or heapBlock is ProtRecBlock containing awaiting queues *)
  247. AppendToMarkList(heapBlock);
  248. END
  249. END
  250. END Inspect;
  251. (** Mark - Mark an object and its decendents. Used by findRoots. *)
  252. PROCEDURE Mark*(p {UNTRACED}: ANY);
  253. VAR orgBlock: ADDRESS; staticTypeBlock {UNTRACED}: StaticTypeBlock;
  254. orgHeapBlock {UNTRACED}: HeapBlock;
  255. currentArrayElemAdr, lastArrayElemAdr: ADDRESS; i: LONGINT;
  256. protected: ProtRecBlock;
  257. b : POINTER {UNSAFE} TO RECORD p: ANY END;
  258. meta: POINTER {UNSAFE} TO RECORD staticTypeBlock {FICTIVE=TypeDescOffset}: StaticTypeBlock; last, current, first: ADDRESS END;
  259. BEGIN
  260. IF Stats THEN INC(Nmark) END;
  261. Inspect(p);
  262. orgHeapBlock := ExtractFromMarkList();
  263. WHILE orgHeapBlock # NIL DO
  264. orgBlock := orgHeapBlock.dataAdr;
  265. meta := orgBlock;
  266. staticTypeBlock := meta.staticTypeBlock;
  267. IF ~(orgHeapBlock IS ArrayBlock) THEN
  268. FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
  269. b := orgBlock + staticTypeBlock.pointerOffsets[i];
  270. Inspect(b.p)
  271. END
  272. ELSE
  273. currentArrayElemAdr := meta.first;
  274. lastArrayElemAdr := meta.first + meta.last * staticTypeBlock.recSize;
  275. IF currentArrayElemAdr > lastArrayElemAdr THEN HALT(100) END;
  276. WHILE currentArrayElemAdr < lastArrayElemAdr DO
  277. FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
  278. b := currentArrayElemAdr + staticTypeBlock.pointerOffsets[i];
  279. Inspect(b.p)
  280. END;
  281. INC(currentArrayElemAdr, staticTypeBlock.recSize);
  282. END
  283. END;
  284. IF orgHeapBlock IS ProtRecBlock THEN
  285. protected := orgHeapBlock(ProtRecBlock);
  286. Inspect(protected.awaitingLock.head);
  287. Inspect(protected.awaitingCond.head);
  288. Inspect(protected.lockedBy);
  289. Inspect(protected.lock);
  290. END;
  291. orgHeapBlock := ExtractFromMarkList();
  292. END;
  293. END Mark;
  294. PROCEDURE MarkRealtimeObjects;
  295. VAR heapBlock {UNTRACED}: HeapBlock;
  296. BEGIN
  297. (*! disable realtime block handling for the time being
  298. first, we have to check that objects cannot move between mark list and realtime list
  299. heapBlock := realtimeList;
  300. WHILE heapBlock # NIL DO
  301. Mark(SYSTEM.VAL(ANY, heapBlock.dataAdr));
  302. heapBlock := heapBlock.nextRealtime;
  303. END;
  304. *)
  305. END MarkRealtimeObjects;
  306. (** WriteType - Write a type name (for tracing only). *)
  307. PROCEDURE WriteType*(t: ADDRESS); (* t is static type descriptor *)
  308. VAR m: ADDRESS; i: LONGINT; ch: CHAR;
  309. typeDesc: StaticTypeBlockU;
  310. BEGIN
  311. typeDesc := t;
  312. m := typeDesc.info.mod;
  313. IF m # NilVal THEN (* could be a type without module, e.g. a Java class *)
  314. i := 0; SYSTEM.GET (m + ModNameOfs + i, ch);
  315. WHILE (ch >= "0") & (ch <= "z") & (i # 32) DO
  316. Trace.Char(ch);
  317. INC(i); SYSTEM.GET (m + ModNameOfs + i, ch)
  318. END
  319. ELSE
  320. Trace.String("NIL")
  321. END;
  322. Trace.Char(".");
  323. IF typeDesc.info.name = "" THEN
  324. Trace.String("-")
  325. ELSE
  326. Trace.String(typeDesc.info.name);
  327. END;
  328. END WriteType;
  329. (** free list handling **)
  330. PROCEDURE ClearFreeLists;
  331. VAR i: LONGINT;
  332. BEGIN
  333. FOR i := 0 TO MaxFreeLists DO
  334. freeLists[i].first := NIL;
  335. freeLists[i].last := NIL
  336. END;
  337. END ClearFreeLists;
  338. (* insert element in fifo, first = freeList.first; last = freeList.last *)
  339. PROCEDURE AppendFree(VAR freeList: FreeList; block: FreeBlock);
  340. BEGIN
  341. ASSERT(block.size >= freeList.minSize);
  342. IF freeList.first = NIL THEN
  343. freeList.first := block; freeList.last := block
  344. ELSE
  345. freeList.last.next := block;
  346. freeList.last := block;
  347. END;
  348. block.next := NIL
  349. END AppendFree;
  350. (* get last element from fifo *)
  351. PROCEDURE GetFree(VAR freeList: FreeList): FreeBlock;
  352. VAR block: FreeBlock;
  353. BEGIN
  354. IF freeList.first = NIL THEN block := NIL;
  355. ELSIF freeList.first = freeList.last THEN block := freeList.first; freeList.first := NIL; freeList.last := NIL
  356. ELSE block := freeList.first; freeList.first := block.next; block.next := NIL
  357. END;
  358. RETURN block
  359. END GetFree;
  360. (** insert sorted into queue, no handling of last queue element *)
  361. PROCEDURE InsertSorted(VAR freeList: FreeList; block: FreeBlock);
  362. VAR x: FreeBlock;
  363. BEGIN
  364. (* keep them ordered to avoid unnecessary splits *)
  365. x := freeList.first;
  366. WHILE x # NIL DO
  367. ASSERT(x # block);
  368. x := x.next;
  369. END;
  370. x := freeList.first;
  371. IF (x = NIL) OR (block.size <= x.size) THEN
  372. block.next := x;
  373. freeList.first := block;
  374. ELSE
  375. WHILE (x.next # NIL) & (block.size > x.next.size) DO x := x.next END;
  376. block.next := x.next;
  377. x.next := block;
  378. END;
  379. END InsertSorted;
  380. PROCEDURE AppendFreeBlock(block: FreeBlock);
  381. VAR i: LONGINT;
  382. BEGIN
  383. i := MaxFreeLists;
  384. WHILE (i > 0) & (freeLists[i].minSize > block.size) DO DEC( i ) END;
  385. IF i < FreeListBarrier THEN
  386. AppendFree(freeLists[i], block);
  387. ELSE
  388. AppendFree(freeLists[i], block);
  389. (*
  390. keeping lists sorted has some positive impact on heap utilization
  391. but it slows down heap allocation speed:
  392. InsertSorted(freeLists[i], block);
  393. *)
  394. END;
  395. END AppendFreeBlock;
  396. PROCEDURE FindFreeBlock( size: SIZE ): FreeBlock;
  397. VAR prev, block: FreeBlock; i: LONGINT;
  398. BEGIN
  399. i := MaxFreeLists;
  400. WHILE (i > 0) & (freeLists[i].minSize > size) DO DEC( i ) END;
  401. REPEAT
  402. IF i < FreeListBarrier THEN
  403. block := GetFree(freeLists[i]);
  404. ELSE
  405. block := freeLists[i].first;
  406. prev := NIL;
  407. WHILE (block # NIL) & (block.size < size) DO
  408. prev := block;
  409. block := block.next;
  410. END;
  411. IF block # NIL THEN (* blockize >= size *)
  412. IF prev = NIL THEN
  413. freeLists[i].first := block.next;
  414. ELSE prev.next := block.next
  415. END;
  416. IF block = freeLists[i].last THEN
  417. freeLists[i].last := prev
  418. END;
  419. block.next := NIL;
  420. END;
  421. (*
  422. prev := freeLists[i].first;
  423. WHILE prev # NIL DO
  424. ASSERT(prev # block);
  425. prev := prev.next;
  426. END;
  427. *)
  428. END;
  429. INC( i )
  430. UNTIL (block # NIL) OR (i > MaxFreeLists);
  431. RETURN block
  432. END FindFreeBlock;
  433. PROCEDURE GetFreeBlockAndSplit(size: SIZE): FreeBlock;
  434. VAR p,remainder: FreeBlockU; adr: ADDRESS;
  435. BEGIN
  436. p := FindFreeBlock(size);
  437. IF (p # NIL) & (ADDRESS(p.size) > ADDRESS (size)) THEN (* block too big - divide block into two parts: block with required size and remaining free block *)
  438. ASSERT(ADDRESS(p.size - size) >= BlockHeaderSize + SIZEOF(FreeBlockDesc));
  439. adr := p;
  440. remainder := adr + size;
  441. InitFreeBlock(remainder, Unmarked, NilVal, p.size - size);
  442. AppendFreeBlock(remainder);
  443. p.size := size;
  444. END;
  445. IF p # NIL THEN INC(freeBlockFound) ELSE INC(freeBlockNotFound) END;
  446. RETURN p
  447. END GetFreeBlockAndSplit;
  448. PROCEDURE GetFreeBlock(size: SIZE; VAR p: FreeBlock);
  449. BEGIN
  450. IF EnableFreeLists THEN
  451. IF sweepMarkValue < currentMarkValue THEN
  452. (*Trace.String("clear free lists and lazy sweep"); Trace.Ln;*)
  453. ClearFreeLists;
  454. LazySweep(MAX(LONGINT), p)
  455. END;
  456. p := GetFreeBlockAndSplit(size)
  457. ELSE
  458. LazySweep(size, p)
  459. END;
  460. IF size # MAX(LONGINT) THEN
  461. INC(throughput, size);
  462. END;
  463. END GetFreeBlock;
  464. (* Sweep phase *)
  465. PROCEDURE LazySweep(size: SIZE; VAR p: FreeBlock);
  466. VAR
  467. lastFreeBlockAdr: ADDRESS; found : BOOLEAN;
  468. block {UNTRACED}: HeapBlock ; freeBlock{UNTRACED}, lastFreeBlock{UNTRACED}: FreeBlock;
  469. blockMark: LONGINT; blockSize: SIZE;
  470. time1, time2: HUGEINT;
  471. CONST FreeBlockHeaderSize = SIZEOF(FreeBlockDesc) + BlockHeaderSize;
  472. BEGIN
  473. time1 := Machine.GetTimer();
  474. ASSERT(~EnableFreeLists OR (size = MAX(LONGINT)));
  475. found := FALSE;
  476. lastFreeBlockAdr := NilVal;
  477. lastFreeBlock := NIL;
  478. IF (sweepMemBlock = NIL) OR (sweepMarkValue < currentMarkValue) THEN (* restart lazy sweep including clearance of lists *)
  479. (* note that the order of the blocks does not necessarily represent the historical order of insertion
  480. as they are potentially provided by the underlying host system in with non-increasing address ranges
  481. blocks are sorted by Machine.Mod in an increased address range order
  482. *)
  483. sweepMemBlock := Machine.memBlockHead;
  484. sweepBlockAdr := Machine.memBlockHead.beginBlockAdr;
  485. sweepMarkValue := currentMarkValue;
  486. END;
  487. WHILE ~found & (sweepMemBlock # NIL) DO
  488. WHILE ~found & (sweepBlockAdr < sweepMemBlock.endBlockAdr) DO
  489. block := SYSTEM.VAL(HeapBlock, sweepBlockAdr + BlockHeaderSize); (* get heap block *)
  490. blockMark := block.mark; (* cache these values since they may be overwritten during concatenation *)
  491. blockSize := block.size;
  492. IF (blockMark < sweepMarkValue) THEN
  493. IF (block IS SystemBlock) OR (block IS RecordBlock) OR (block IS ProtRecBlock) OR (block IS ArrayBlock) THEN
  494. freeBlock := SYSTEM.VAL(FreeBlock, block);
  495. InitFreeBlock(freeBlock, Unmarked, NilVal, blockSize); (* convert this block into a free heap block and clear its data *)
  496. Machine.Fill32(sweepBlockAdr + FreeBlockHeaderSize, blockSize - FreeBlockHeaderSize, DebugValue);
  497. ELSE
  498. ASSERT(block IS FreeBlock);
  499. freeBlock := block(FreeBlock); (* free block has data cleared by definition *)
  500. END;
  501. IF lastFreeBlockAdr = NilVal THEN
  502. lastFreeBlockAdr := sweepBlockAdr;
  503. lastFreeBlock := freeBlock;
  504. ELSIF lastFreeBlockAdr + lastFreeBlock.size = sweepBlockAdr THEN
  505. (* there are two contiguous free blocks - merge them *)
  506. INC(lastFreeBlock.size,blockSize);
  507. (* clear header fields of concatenated block *)
  508. Machine.Fill32(sweepBlockAdr, FreeBlockHeaderSize, DebugValue);
  509. END
  510. ELSE
  511. ASSERT(~(block IS FreeBlock));
  512. END;
  513. IF (blockMark >= sweepMarkValue) OR (sweepBlockAdr + blockSize = sweepMemBlock.endBlockAdr) THEN (* no further merging is possible *)
  514. ASSERT(sweepBlockAdr + blockSize <= sweepMemBlock.endBlockAdr);
  515. IF lastFreeBlockAdr # NilVal THEN
  516. IF ADDRESS(lastFreeBlock.size) >= ADDRESS (size) THEN (* block found - may be too big *)
  517. p := lastFreeBlock;
  518. IF ADDRESS(p.size) > ADDRESS (size) THEN (* block too big - divide block into two parts: block with required size and remaining free block *)
  519. ASSERT(ADDRESS(p.size - size) >= FreeBlockHeaderSize);
  520. freeBlock := SYSTEM.VAL(FreeBlock, SYSTEM.VAL(ADDRESS, p) + size);
  521. InitFreeBlock(freeBlock, Unmarked, NilVal, p.size - size);
  522. p.size := size;
  523. END;
  524. sweepBlockAdr := lastFreeBlockAdr + size; (* make sure next lazy sweep continues after block p *)
  525. found := TRUE;
  526. ELSIF EnableFreeLists THEN AppendFreeBlock(lastFreeBlock);
  527. END;
  528. lastFreeBlockAdr := NilVal;
  529. lastFreeBlock := NIL;
  530. END
  531. END;
  532. IF ~found THEN sweepBlockAdr := sweepBlockAdr + blockSize END
  533. END;
  534. IF ~found THEN
  535. sweepMemBlock := sweepMemBlock.next;
  536. IF sweepMemBlock # NIL THEN
  537. sweepBlockAdr := sweepMemBlock.beginBlockAdr
  538. ELSE
  539. sweepBlockAdr := NilVal
  540. END
  541. END
  542. END;
  543. time2 := Machine.GetTimer()-time1;
  544. INC(NgcSweepTime, time2);
  545. IF time2 > NgcSweepMax THEN NgcSweepMax := time2 END;
  546. END LazySweep;
  547. (* -- useful for debugging --
  548. PROCEDURE CheckHeap;
  549. VAR memBlock {UNTRACED}: Machine.MemoryBlock; p, refBlock, currentArrayElemAdr, lastArrayElemAdr: ADDRESS;
  550. heapBlock {UNTRACED}: HeapBlock; staticTypeBlock {UNTRACED}: StaticTypeBlock; i: LONGINT;
  551. PROCEDURE CheckBlock(block: ADDRESS): BOOLEAN;
  552. VAR heapBlockAdr: ADDRESS;
  553. BEGIN
  554. IF block = NilVal THEN
  555. RETURN TRUE
  556. ELSE
  557. IF (block >= Machine.memBlockHead.beginBlockAdr) & (block < Machine.memBlockTail.endBlockAdr) THEN
  558. SYSTEM.GET(block + HeapBlockOffset, heapBlockAdr);
  559. IF (heapBlockAdr >= Machine.memBlockHead.beginBlockAdr) & (heapBlockAdr < Machine.memBlockTail.endBlockAdr) THEN
  560. RETURN TRUE
  561. ELSE
  562. RETURN FALSE
  563. END
  564. ELSE
  565. RETURN FALSE
  566. END
  567. END
  568. END CheckBlock;
  569. BEGIN
  570. memBlock := Machine.memBlockHead;
  571. WHILE memBlock # NIL DO
  572. p := memBlock.beginBlockAdr;
  573. WHILE p < memBlock.endBlockAdr DO
  574. heapBlock := SYSTEM.VAL(HeapBlock, p + BlockHeaderSize);
  575. IF heapBlock IS SystemBlock THEN
  576. ELSIF heapBlock IS RecordBlock THEN
  577. IF heapBlock.dataAdr # NilVal THEN
  578. SYSTEM.GET(heapBlock.dataAdr + TypeDescOffset, staticTypeBlock); ASSERT(staticTypeBlock # NIL);
  579. FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
  580. SYSTEM.GET(heapBlock.dataAdr + staticTypeBlock.pointerOffsets[i], refBlock);
  581. IF ~CheckBlock(refBlock) THEN
  582. Trace.String("SEVERE ERROR: RecordBlock = "); Trace.Hex(heapBlock.dataAdr, 8);
  583. Trace.String(" invalid reference at pointer offset = "); Trace.Hex(staticTypeBlock.pointerOffsets[i], 0); Trace.Ln
  584. END
  585. END;
  586. IF heapBlock IS ProtRecBlock THEN
  587. IF CheckBlock(heapBlock(ProtRecBlock).awaitingLock.head) &
  588. CheckBlock(heapBlock(ProtRecBlock).awaitingLock.tail) &
  589. CheckBlock(heapBlock(ProtRecBlock).awaitingCond.head) &
  590. CheckBlock(heapBlock(ProtRecBlock).awaitingCond.tail) &
  591. CheckBlock(heapBlock(ProtRecBlock).lockedBy) THEN
  592. ELSE
  593. Trace.String("SEVERE ERROR in awaiting queues of block = "); Trace.Hex(heapBlock.dataAdr, 8); Trace.Ln
  594. END
  595. END
  596. ELSE
  597. Trace.StringLn("SEVERE ERROR: heapBlock.dataAdr = NilVal for RecordBlock or ProtRecBlock")
  598. END;
  599. ELSIF heapBlock IS ArrayBlock THEN
  600. IF heapBlock.dataAdr # NilVal THEN
  601. SYSTEM.GET(heapBlock.dataAdr + TypeDescOffset, staticTypeBlock); ASSERT(staticTypeBlock # NIL);
  602. SYSTEM.GET(heapBlock.dataAdr + 2 * AddressSize, currentArrayElemAdr);
  603. SYSTEM.GET(heapBlock.dataAdr, lastArrayElemAdr);
  604. WHILE currentArrayElemAdr <= lastArrayElemAdr DO
  605. FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
  606. SYSTEM.GET(currentArrayElemAdr + staticTypeBlock.pointerOffsets[i], refBlock);
  607. IF ~CheckBlock(refBlock) THEN
  608. Trace.String("SEVERE ERROR in ArrayBlock = "); Trace.Hex(currentArrayElemAdr, 8);
  609. Trace.String(" invalid reference at pointer offset = "); Trace.Hex(staticTypeBlock.pointerOffsets[i], 0); Trace.Ln
  610. END
  611. END;
  612. INC(currentArrayElemAdr, staticTypeBlock.recSize)
  613. END
  614. ELSE
  615. Trace.StringLn("SEVERE ERROR: heapBlock.dataAdr = NilVal for ArrayBlock")
  616. END
  617. ELSIF heapBlock IS FreeBlock THEN
  618. ELSE
  619. Trace.StringLn("Invalid heap block type")
  620. END;
  621. p := p + heapBlock.size;
  622. END;
  623. memBlock := memBlock.next
  624. END
  625. END CheckHeap;
  626. *)
  627. (* CheckCandidates - Check which candidates could be pointers, and mark them. (exported for debugging only) *)
  628. PROCEDURE CheckCandidates*;
  629. CONST MinDataOffset = BlockHeaderSize + SIZEOF(HeapBlockDesc) + BlockHeaderSize; (* minimal offset of data address with respect to block start address *)
  630. VAR i, j, h: LONGINT; p, blockStart: ADDRESS; memBlock {UNTRACED}: Machine.MemoryBlock;
  631. heapBlock {UNTRACED}: HeapBlock;
  632. BEGIN
  633. (* {numCandidates > 0} *)
  634. (* first sort them in increasing order using shellsort *)
  635. h := 1; REPEAT h := h*3 + 1 UNTIL h > numCandidates;
  636. REPEAT
  637. h := h DIV 3; i := h;
  638. WHILE i < numCandidates DO
  639. p := candidates[i]; j := i;
  640. WHILE (j >= h) & (candidates[j-h] > p) DO
  641. candidates[j] := candidates[j-h]; j := j-h;
  642. END;
  643. candidates[j] := p; INC(i)
  644. END
  645. UNTIL h = 1;
  646. (* sweep phase *)
  647. i := 0;
  648. p := candidates[i];
  649. memBlock := Machine.memBlockHead;
  650. WHILE memBlock # NIL DO
  651. blockStart := memBlock.beginBlockAdr;
  652. WHILE (i < numCandidates) & (blockStart < memBlock.endBlockAdr) DO
  653. IF p < blockStart + MinDataOffset THEN (* candidate missed *)
  654. INC(i);
  655. IF i < numCandidates THEN
  656. p := candidates[i]
  657. END
  658. ELSE
  659. heapBlock := SYSTEM.VAL(HeapBlock, blockStart + BlockHeaderSize);
  660. IF (p = heapBlock.dataAdr) & ~(heapBlock IS FreeBlock) THEN (* heap block must not be a free block but any other heap block type *)
  661. Mark(SYSTEM.VAL(ANY, p))
  662. END;
  663. blockStart := blockStart + heapBlock.size;
  664. END
  665. END;
  666. memBlock := memBlock.next
  667. END;
  668. numCandidates := 0
  669. END CheckCandidates;
  670. (* Check validity of single pointer candidate and enter it into the list of candidates *)
  671. PROCEDURE Candidate*(p: ADDRESS);
  672. VAR memBlock, memBlockX {UNTRACED}: Machine.MemoryBlock;
  673. tdAdr, heapBlockAdr: ADDRESS;
  674. tdPtr: POINTER {UNSAFE} TO RECORD typeAdr: ADDRESS END;
  675. hbPtr: POINTER {UNSAFE} TO RECORD heapBlock: HeapBlock END;
  676. heapBlock {UNTRACED}: HeapBlock;
  677. BEGIN
  678. IF p MOD SIZEOF(ADDRESS) # 0 THEN RETURN END;
  679. IF (p >= Machine.memBlockHead.beginBlockAdr) & (p < Machine.memBlockTail.endBlockAdr) THEN
  680. memBlock := Machine.memBlockHead;
  681. WHILE memBlock # NIL DO
  682. IF (p + HeapBlockOffset >= memBlock.beginBlockAdr) & (p + HeapBlockOffset < memBlock.endBlockAdr) THEN
  683. hbPtr := p + HeapBlockOffset;
  684. heapBlock := hbPtr.heapBlock;
  685. heapBlockAdr := heapBlock ;
  686. IF heapBlockAdr MOD SIZEOF(ADDRESS) # 0 THEN RETURN END;
  687. tdAdr :=heapBlockAdr + TypeDescOffset;
  688. (* check if tdAdr is a valid pointer in the heap *)
  689. memBlockX := Machine.memBlockHead;
  690. WHILE memBlockX # NIL DO
  691. IF (tdAdr >= memBlockX.beginBlockAdr) & (tdAdr < memBlockX.endBlockAdr) THEN
  692. (* IF (heapBlock.mark >= currentMarkValue) THEN RETURN END;*)
  693. tdPtr := tdAdr;
  694. tdAdr := tdPtr.typeAdr;
  695. (* check whether tdAdr is a valid type descriptor address *)
  696. IF (tdAdr = systemBlockTag) OR (tdAdr = recordBlockTag) OR (tdAdr = protRecBlockTag) OR (tdAdr = arrayBlockTag) THEN
  697. candidates[numCandidates] := p;
  698. INC(numCandidates);
  699. IF numCandidates = LEN(candidates) THEN CheckCandidates END
  700. END;
  701. RETURN; (* found *)
  702. END;
  703. memBlockX := memBlockX.next
  704. END;
  705. RETURN; (* not found *)
  706. END;
  707. memBlock := memBlock.next
  708. END
  709. END
  710. END Candidate;
  711. (** RegisterCandidates - Register a block of pointer candidates *)
  712. PROCEDURE RegisterCandidates*(adr: ADDRESS; size: SIZE);
  713. VAR end, p: ADDRESS;
  714. BEGIN
  715. (* current processor must hold Heaps lock *)
  716. end := adr + size;
  717. WHILE adr # end DO
  718. SYSTEM.GET(adr, p);
  719. Candidate(p);
  720. INC(adr, AddressSize)
  721. END
  722. END RegisterCandidates;
  723. (* Check reachability of finalized objects. *)
  724. PROCEDURE CheckFinalizedObjects;
  725. VAR n, p, t: FinalizerNode; heapBlock {UNTRACED}: HeapBlock;
  726. PROCEDURE MarkDelegate(p: Finalizer);
  727. VAR pointer: ANY;
  728. BEGIN
  729. SYSTEM.GET(ADDRESSOF(p)+SIZEOF(ADDRESS),pointer);
  730. IF pointer # NIL THEN Mark(pointer) END;
  731. END MarkDelegate;
  732. BEGIN
  733. n := checkRoot;
  734. WHILE n # NIL DO (* move unmarked checked objects to finalize list *)
  735. SYSTEM.GET(SYSTEM.VAL(ADDRESS, n.objWeak) + HeapBlockOffset, heapBlock);
  736. IF heapBlock.mark < currentMarkValue THEN
  737. IF n = checkRoot THEN checkRoot := n.nextFin ELSE p.nextFin := n.nextFin END;
  738. n.objStrong := n.objWeak; (* anchor the object for finalization *)
  739. n.finalizerStrong := n.finalizer; (* anchor the finalizer for finalization *)
  740. t := n.nextFin; n.nextFin := finalizeRoot; finalizeRoot := n; n := t;
  741. IF Stats THEN DEC(NfinalizeAlive); INC(NfinalizeDead) END
  742. ELSE
  743. p := n; n := n.nextFin
  744. END
  745. END;
  746. (* now trace the weak references to keep finalized objects alive during this collection *)
  747. n := finalizeRoot;
  748. WHILE n # NIL DO
  749. MarkDelegate(n.finalizerStrong);
  750. Mark(n.objStrong); n := n.nextFin
  751. END;
  752. n := checkRoot;
  753. WHILE n # NIL DO (* list of objects that had been marked before entering CheckFinalizedObjects *)
  754. (* we still have to mark the weak finalizers, as they might have not been marked before *)
  755. MarkDelegate(n.finalizer); n := n.nextFin
  756. END;
  757. END CheckFinalizedObjects;
  758. (** Return the next scheduled finalizer or NIL if none available. Called by finalizer object in Kernel. *)
  759. PROCEDURE GetFinalizer* (): FinalizerNode;
  760. VAR n: FinalizerNode;
  761. BEGIN
  762. n := NIL;
  763. IF finalizeRoot # NIL THEN
  764. Machine.Acquire(Machine.Heaps);
  765. n := finalizeRoot; (* take one finalizer *)
  766. IF n # NIL THEN
  767. finalizeRoot := n.nextFin; n.nextFin := NIL;
  768. IF Stats THEN DEC(NfinalizeDead) END;
  769. END;
  770. Machine.Release(Machine.Heaps);
  771. END;
  772. RETURN n
  773. END GetFinalizer;
  774. (** Check finalizers registered in the specified module, which is about to be freed or shut down. Remove all finalizer procedures in this module from the finalizer lists so they won't be called any more. *)
  775. PROCEDURE CleanupModuleFinalizers*(codeAdr: ADDRESS; codeLen: SIZE; CONST name: ARRAY OF CHAR);
  776. VAR n, p, t: FinalizerNode; codeEnd: ADDRESS; N1, N2: LONGINT;
  777. BEGIN
  778. codeEnd := codeAdr + codeLen; N1 := 0; N2 := 0;
  779. Machine.Acquire(Machine.Heaps);
  780. n := checkRoot;
  781. WHILE n # NIL DO (* iterate over checked list *)
  782. t := n; n := n.nextFin;
  783. IF (codeAdr <= SYSTEM.VAL (ADDRESS, t.finalizer)) & (SYSTEM.VAL (ADDRESS, t.finalizer) <= codeEnd) THEN
  784. IF t = checkRoot THEN checkRoot := t.nextFin ELSE p.nextFin := t.nextFin END; (* remove from list *)
  785. IF Stats THEN DEC(NfinalizeAlive) END;
  786. INC(N1)
  787. ELSE
  788. p := t
  789. END
  790. END;
  791. (* also remove finalizers from list, so they won't be called *)
  792. n := finalizeRoot;
  793. WHILE n # NIL DO (* iterate over finalized list *)
  794. t := n; n := n.nextFin;
  795. IF (codeAdr <= SYSTEM.VAL (ADDRESS, t.finalizer)) & (SYSTEM.VAL (ADDRESS, t.finalizer) <= codeEnd) THEN
  796. IF t = finalizeRoot THEN finalizeRoot := t.nextFin ELSE p.nextFin := t.nextFin END; (* remove from list *)
  797. IF Stats THEN DEC(NfinalizeDead) END;
  798. INC(N2)
  799. ELSE
  800. p := t
  801. END
  802. END;
  803. Machine.Release(Machine.Heaps);
  804. IF (N1 # 0) OR (N2 # 0) THEN
  805. Machine.Acquire (Machine.TraceOutput);
  806. Trace.String(name); Trace.Char(" ");
  807. Trace.Int(N1, 1); Trace.String(" discarded finalizers, ");
  808. Trace.Int(N2, 1); Trace.StringLn (" pending finalizers");
  809. Machine.Release (Machine.TraceOutput);
  810. END
  811. END CleanupModuleFinalizers;
  812. (* Add a root object to the set of traversable objects. If in allocated heap then mark and traverse, if in Module Heap (Bootfile) then only traverse. *)
  813. PROCEDURE AddRootObject*(rootObject: RootObject);
  814. BEGIN
  815. IF rootObject = NIL THEN (* nothing *)
  816. ELSIF CheckPointer(rootObject) THEN
  817. (* object in heap, must be fully marked and traversed *)
  818. Mark(rootObject)
  819. ELSE
  820. (* object in bootfile, traverse as root object only *)
  821. rootObject.nextRoot := rootList; rootList := rootObject; (* link root list *)
  822. END;
  823. END AddRootObject;
  824. (* interruptible garbage collector for native A2 *)
  825. PROCEDURE CollectGarbage*(root : RootObject);
  826. VAR
  827. obj: RootObject;
  828. time1, time2: HUGEINT;
  829. f: FreeBlock;
  830. BEGIN
  831. (* do never use any low level locks as the garbage collector process has a very high priority and may thus be blocked by lower level processes -> potential deadlock *)
  832. (*!
  833. Do not use windows functionality such as trace here in general -- can lead to deadlock when stopped processes are in writing to a file
  834. *)
  835. (* GC may run only if and only if sweep phase has been completed *)
  836. IF ~EnableFreeLists OR (sweepMemBlock = NIL) & (sweepMarkValue = currentMarkValue) THEN
  837. IF Stats THEN
  838. Nmark := 0; Nmarked := 0;
  839. INC(Ngc);
  840. time1 := Machine.GetTimer ();
  841. END;
  842. numCandidates := 0;
  843. rootList := NIL;
  844. INC(currentMarkValue);
  845. AddRootObject(root);
  846. IF GCType = HeuristicStackInspectionGC THEN
  847. REPEAT
  848. REPEAT
  849. IF rootList # NIL THEN (* check root objects *)
  850. REPEAT
  851. obj := rootList; (* get head object *)
  852. rootList := rootList.nextRoot; (* link to next *)
  853. obj.FindRoots; (* Mark called via AddRootObject, but not for objects in static heap *)
  854. UNTIL rootList = NIL
  855. END;
  856. IF numCandidates # 0 THEN CheckCandidates END
  857. UNTIL (numCandidates = 0) & (rootList = NIL);
  858. MarkRealtimeObjects;
  859. CheckFinalizedObjects;
  860. UNTIL rootList = NIL;
  861. ELSIF GCType = MetaDataForStackGC THEN
  862. REPEAT
  863. IF rootList # NIL THEN (* check root objects *)
  864. REPEAT
  865. obj := rootList; (* get head object *)
  866. rootList := rootList.nextRoot; (* link to next *)
  867. obj.FindRoots; (* Mark called via AddRootObject, but not for objects in static heap *)
  868. UNTIL rootList = NIL
  869. END;
  870. MarkRealtimeObjects;
  871. CheckFinalizedObjects
  872. UNTIL rootList = NIL;
  873. ELSE
  874. HALT(901) (* wrong GCType constant *)
  875. END;
  876. IF Stats THEN
  877. time2 := Machine.GetTimer ();
  878. NgcCyclesLastRun := time2 - time1;
  879. IF NgcCyclesLastRun > NgcCyclesMax THEN NgcCyclesMax := NgcCyclesLastRun; END;
  880. INC(NgcCyclesAllRuns, NgcCyclesLastRun);
  881. NgcCyclesMark := NgcCyclesLastRun
  882. END;
  883. END;
  884. IF EnableFreeLists THEN GetFreeBlock(MAX(LONGINT), f) END;
  885. END CollectGarbage;
  886. PROCEDURE InvokeGC*;
  887. BEGIN
  888. ASSERT(gcStatus # NIL);
  889. gcStatus.SetgcOngoing(TRUE);
  890. END InvokeGC;
  891. PROCEDURE ReturnBlocks;
  892. VAR memBlock {UNTRACED}, free{UNTRACED}: Machine.MemoryBlock; p: ADDRESS; heapBlock {UNTRACED}: HeapBlock; f: FreeBlock;
  893. BEGIN
  894. GetFreeBlock(MAX(LONGINT), f);
  895. memBlock := Machine.memBlockHead;
  896. WHILE memBlock # NIL DO
  897. free := NIL;
  898. p := memBlock.beginBlockAdr;
  899. heapBlock := SYSTEM.VAL(HeapBlock, p + BlockHeaderSize);
  900. IF (heapBlock IS FreeBlock) & (p + heapBlock.size = memBlock.endBlockAdr) THEN
  901. free := memBlock;
  902. END;
  903. memBlock := memBlock.next;
  904. IF free # NIL THEN
  905. Machine.FreeMemBlock(free)
  906. END;
  907. END;
  908. sweepMemBlock := NIL; (* restart LazySweep *)
  909. ClearFreeLists;
  910. END ReturnBlocks;
  911. PROCEDURE LazySweepGC*;
  912. VAR p {UNTRACED}: FreeBlock;
  913. BEGIN
  914. (* invoke mark phase, mark phase starts at next scheduler interrupt *)
  915. GC;
  916. (* return blocks now *)
  917. Machine.Acquire(Machine.Heaps);
  918. (* trying to satisfy a request of MAX(LONGINT) bytes will never succeed - lazy sweep runs until end of heap *)
  919. GetFreeBlock(MAX(LONGINT), p);
  920. IF EnableReturnBlocks THEN ReturnBlocks END;
  921. Machine.Release(Machine.Heaps);
  922. END LazySweepGC;
  923. (* initialize a free heap block *)
  924. PROCEDURE InitFreeBlock(freeBlock: FreeBlock; mark: LONGINT; dataAdr: ADDRESS; size: SIZE);
  925. BEGIN
  926. freeBlock.mark := mark;
  927. freeBlock.dataAdr := dataAdr;
  928. freeBlock.size := size;
  929. freeBlock.next := NIL;
  930. (* initialize heap block header *)
  931. freeBlock.typeDesc := freeBlockTag;
  932. freeBlock.heapBlock := NIL;
  933. END InitFreeBlock;
  934. VAR throughput := 0 : SIZE;
  935. (* NewBlock - Allocate a heap block. {(size MOD BlockSize = 0)}. Caller must hold Heap lock. *)
  936. PROCEDURE NewBlock(size: SIZE): ADDRESS;
  937. VAR try: LONGINT; p: FreeBlock; freeBlock : FreeBlockU; memBlock {UNTRACED}: Machine.MemoryBlock;
  938. beginHeapBlockAdr, endHeapBlockAdr: ADDRESS;
  939. PROCEDURE CheckPostGC;
  940. BEGIN
  941. IF (sweepMarkValue < currentMarkValue) & EnableReturnBlocks THEN (* GC has run but no Sweep yet -- time to do post-gc cleanup *)
  942. ReturnBlocks
  943. END;
  944. END CheckPostGC;
  945. BEGIN
  946. CheckPostGC;
  947. try := 1;
  948. p := NIL;
  949. IF (GC = NilGC) OR (throughput < 64*1024*1024) THEN
  950. GetFreeBlock(size, p);
  951. ELSE
  952. throughput := 0;
  953. END;
  954. WHILE (p = NIL) & (try <= MaxTries) DO
  955. Machine.Release(Machine.Heaps); (* give up control *)
  956. GC; (* try to free memory (other processes may also steal memory now) *)
  957. Machine.Acquire(Machine.Heaps);
  958. CheckPostGC;
  959. sweepMemBlock := NIL;
  960. GetFreeBlock(size, p);
  961. IF p = NIL THEN
  962. Machine.ExpandHeap(try, size, memBlock, beginHeapBlockAdr, endHeapBlockAdr); (* try to extend the heap *)
  963. IF endHeapBlockAdr > beginHeapBlockAdr THEN
  964. freeBlock := beginHeapBlockAdr + BlockHeaderSize;
  965. InitFreeBlock(freeBlock, Unmarked, NilVal, endHeapBlockAdr - beginHeapBlockAdr);
  966. Machine.SetMemoryBlockEndAddress(memBlock, endHeapBlockAdr); (* end address of expanded block must set after free block is fit in memory block *)
  967. IF EnableFreeLists THEN AppendFreeBlock(freeBlock)
  968. ELSE
  969. sweepMemBlock := memBlock;
  970. sweepBlockAdr := beginHeapBlockAdr;
  971. END;
  972. GetFreeBlock(size, p);
  973. sweepMemBlock := NIL; (* restart sweep from beginning after having taken big block in order to avoid fragmentation *)
  974. END;
  975. INC(try)
  976. END;
  977. END;
  978. IF p # NIL THEN
  979. IF Stats THEN INC(Nnew); INC(NnewBytes, size) END;
  980. ASSERT(p.size >= size);
  981. RETURN p;
  982. ELSE (* try = MaxTries *)
  983. SYSTEM.HALT(14) (* out of memory *)
  984. END;
  985. END NewBlock;
  986. PROCEDURE CheckBP(bp: ADDRESS): ADDRESS;
  987. VAR n: ADDRESS;
  988. BEGIN
  989. SYSTEM.GET(bp,n);
  990. IF ODD(n) THEN bp := bp + SIZEOF(ADDRESS) END;
  991. RETURN bp;
  992. END CheckBP;
  993. PROCEDURE SetPC(p: DataBlockU);
  994. VAR bp: ADDRESS;
  995. BEGIN
  996. IF p # NIL THEN
  997. bp := CheckBP(Machine.CurrentBP());
  998. SYSTEM.GET(bp, bp);
  999. bp := CheckBP(bp);
  1000. SYSTEM.GET(bp+SIZEOF(ADDRESS), p.heapBlock.heapBlock);
  1001. END;
  1002. END SetPC;
  1003. (** NewSys - Implementation of SYSTEM.NEW. *)
  1004. PROCEDURE NewSys*(VAR p: ANY; size: SIZE; isRealtime: BOOLEAN);
  1005. VAR
  1006. blockSize, systemBlockSize: SIZE; systemBlockAdr, dataBlockAdr: ADDRESS;
  1007. systemBlock: HeapBlockU;
  1008. dataBlock: DataBlockU;
  1009. BEGIN
  1010. systemBlockSize := BlockHeaderSize + SIZEOF(SystemBlockDesc);
  1011. INC(systemBlockSize, (-systemBlockSize) MOD ArrayAlignment); (* round up to multiple of ArrayAlignment to ensure alignment of first data element to 0 MOD ArrayAlignment *)
  1012. blockSize := systemBlockSize + BlockHeaderSize + size;
  1013. INC(blockSize, (-blockSize) MOD BlockSize); (* round up to multiple of BlockSize *)
  1014. Machine.Acquire(Machine.Heaps);
  1015. systemBlockAdr:= NewBlock(blockSize);
  1016. IF systemBlockAdr # 0 THEN
  1017. systemBlock := systemBlockAdr;
  1018. dataBlockAdr := systemBlockAdr + systemBlockSize;
  1019. dataBlock := dataBlockAdr;
  1020. systemBlock.typeDesc := systemBlockTag;
  1021. dataBlock.typeDesc := NilVal;
  1022. dataBlock.heapBlock := systemBlock;
  1023. systemBlock.mark := currentMarkValue;
  1024. systemBlock.dataAdr := dataBlockAdr;
  1025. systemBlock.size := blockSize;
  1026. (*! disable realtime block handling for the time being
  1027. IF isRealtime THEN
  1028. systemBlock.nextRealtime := realtimeList;
  1029. realtimeList := systemBlock
  1030. ELSE
  1031. systemBlock.nextRealtime := NIL
  1032. END;
  1033. *)
  1034. SetPC(dataBlock);
  1035. p := dataBlock;
  1036. (* clear could be done outside lock because SysBlks are not traced, but for conformity it is done inside the lock *)
  1037. Machine.Fill32(dataBlockAdr, blockSize - systemBlockSize - BlockHeaderSize, 0); (* clear everything from dataBlockAdr until end of block *)
  1038. ELSE
  1039. p := NIL
  1040. END;
  1041. IF allocationLogger # NIL THEN allocationLogger(p) END;
  1042. Machine.Release(Machine.Heaps)
  1043. END NewSys;
  1044. (** NewRec - Implementation of NEW with a record. *)
  1045. PROCEDURE NewRec*(VAR p: ANY; tag: ADDRESS; isRealtime: BOOLEAN);
  1046. VAR
  1047. size, blockSize: SIZE; recordBlockAdr, dataBlockAdr : ADDRESS;
  1048. recordBlock: RecordBlockU;
  1049. dataBlock: DataBlockU;
  1050. typeDesc: StaticTypeBlockU;
  1051. BEGIN
  1052. typeDesc := tag;
  1053. IF ProtTypeBit IN typeDesc.info.flags THEN
  1054. NewProtRec(p, tag, isRealtime);
  1055. SetPC(p);
  1056. ELSE
  1057. size := typeDesc.recSize;
  1058. (* the block size is the sum of the size of the RecordBlock and the DataBlock.
  1059. Two extra fields per subblock contain the tag and the reference to the heap block *)
  1060. blockSize := BlockHeaderSize + SIZEOF(RecordBlockDesc) + BlockHeaderSize + size;
  1061. INC(blockSize, (-blockSize) MOD BlockSize); (* round up to multiple of BlockSize *)
  1062. Machine.Acquire(Machine.Heaps);
  1063. recordBlockAdr := NewBlock(blockSize);
  1064. IF recordBlockAdr # 0 THEN
  1065. recordBlock := recordBlockAdr;
  1066. dataBlockAdr := recordBlockAdr + SIZEOF(RecordBlockDesc) + BlockHeaderSize;
  1067. dataBlock := dataBlockAdr;
  1068. recordBlock.typeDesc := recordBlockTag;
  1069. dataBlock.typeDesc := tag;
  1070. dataBlock.heapBlock := recordBlockAdr;
  1071. recordBlock.mark := currentMarkValue;
  1072. recordBlock.dataAdr := dataBlockAdr;
  1073. recordBlock.size := blockSize;
  1074. (*! disable realtime block handling for the time being
  1075. IF isRealtime THEN
  1076. recordBlock.nextRealtime := realtimeList;
  1077. realtimeList := recordBlock
  1078. ELSE
  1079. recordBlock.nextRealtime := NIL
  1080. END;
  1081. *)
  1082. SetPC(dataBlock);
  1083. p := dataBlock;
  1084. (* clear must be done inside lock to ensure all traced pointer fields are initialized to NIL *)
  1085. Machine.Fill32(dataBlockAdr, blockSize - SIZEOF(RecordBlockDesc) - 2 * BlockHeaderSize, 0); (* clear everything from dataBlockAdr until end of block *)
  1086. ELSE
  1087. p := NIL
  1088. END;
  1089. IF allocationLogger # NIL THEN allocationLogger(p) END;
  1090. Machine.Release(Machine.Heaps)
  1091. END;
  1092. END NewRec;
  1093. (** NewProtRec - Implementation of NEW with a protected record. *)
  1094. PROCEDURE NewProtRec*(VAR p: ANY; tag: ADDRESS; isRealtime: BOOLEAN);
  1095. VAR size, blockSize: SIZE; protRecBlockAdr, dataBlockAdr: ADDRESS;
  1096. protRecBlock: ProtRecBlockU;
  1097. dataBlock: DataBlockU;
  1098. i: LONGINT;
  1099. typeDesc: StaticTypeBlockU;
  1100. BEGIN
  1101. typeDesc := tag;
  1102. size := typeDesc.recSize;
  1103. blockSize := BlockHeaderSize + SIZEOF(ProtRecBlockDesc) + BlockHeaderSize + size;
  1104. INC(blockSize, (-blockSize) MOD BlockSize); (* round up to multiple of BlockSize *)
  1105. Machine.Acquire(Machine.Heaps);
  1106. protRecBlockAdr := NewBlock(blockSize);
  1107. IF protRecBlockAdr # 0 THEN
  1108. protRecBlock := protRecBlockAdr;
  1109. dataBlockAdr := protRecBlockAdr + SIZEOF(ProtRecBlockDesc) + BlockHeaderSize;
  1110. dataBlock := dataBlockAdr;
  1111. protRecBlock.typeDesc := protRecBlockTag;
  1112. dataBlock.typeDesc := tag;
  1113. dataBlock.heapBlock := protRecBlockAdr;
  1114. protRecBlock.mark := currentMarkValue;
  1115. protRecBlock.dataAdr := dataBlockAdr;
  1116. protRecBlock.size := blockSize;
  1117. (*! disable realtime block handling for the time being
  1118. IF isRealtime THEN
  1119. protRecBlock.nextRealtime := realtimeList;
  1120. realtimeList := protRecBlock
  1121. ELSE
  1122. protRecBlock.nextRealtime := NIL
  1123. END;
  1124. *)
  1125. protRecBlock.count := 0;
  1126. protRecBlock.awaitingLock.head := NIL;
  1127. protRecBlock.awaitingLock.tail := NIL;
  1128. protRecBlock.awaitingCond.head := NIL;
  1129. protRecBlock.awaitingCond.tail := NIL;
  1130. protRecBlock.lockedBy := NIL;
  1131. protRecBlock.locked := FALSE;
  1132. protRecBlock.lock := NIL;
  1133. FOR i := 0 TO NumPriorities - 1 DO
  1134. protRecBlock.waitingPriorities[i] := 0
  1135. END;
  1136. INC(protRecBlock.waitingPriorities[0]); (* set sentinel value: assume that idle process with priority 0 waits on this resource *)
  1137. SetPC(dataBlock);
  1138. p := dataBlock;
  1139. (* clear must be done inside lock to ensure all traced pointer fields are initialized to NIL *)
  1140. Machine.Fill32(dataBlockAdr, blockSize - SIZEOF(ProtRecBlockDesc) - 2 * BlockHeaderSize, 0); (* clear everything from dataBlockAdr to end of block *)
  1141. ELSE
  1142. p := NIL
  1143. END;
  1144. IF allocationLogger # NIL THEN allocationLogger(p) END;
  1145. Machine.Release(Machine.Heaps)
  1146. END NewProtRec;
  1147. (** NewArr - Implementation of NEW with an array containing pointers. *)
  1148. PROCEDURE NewArr*(VAR p: ANY; elemTag: ADDRESS; numElems, numDims: SIZE; isRealtime: BOOLEAN);
  1149. VAR arrayBlockAdr, dataBlockAdr: ADDRESS;
  1150. elemSize, arrSize, blockSize, arrayBlockSize, fillSize, size, arrayDataOffset: SIZE;
  1151. firstElem: ADDRESS;
  1152. ptrOfs: ADDRESS;
  1153. elemType: StaticTypeBlockU;
  1154. arrayBlock: ArrayBlockU;
  1155. dataBlock: ArrayDataBlockU;
  1156. BEGIN
  1157. elemType := elemTag;
  1158. elemSize := elemType.recSize;
  1159. arrSize := numElems * elemSize;
  1160. IF arrSize = 0 THEN
  1161. NewSys(p, numDims * AddressSize + 3 * AddressSize, isRealtime); (* no data, thus no specific alignment *)
  1162. SetPC(p);
  1163. ELSE
  1164. ASSERT(BlockHeaderSize MOD ArrayAlignment = 0);
  1165. arrayDataOffset := numDims * AddressSize + 3 * AddressSize;
  1166. INC(arrayDataOffset, (-arrayDataOffset) MOD ArrayAlignment); (* round up to multiple of ArrayAlignment to ensure that first array element is aligned at 0 MOD ArrayAlignment *)
  1167. ptrOfs := elemType.pointerOffsets;
  1168. IF ptrOfs = MinPtrOfs - AddressSize THEN (* no pointers in element type *)
  1169. size := arrayDataOffset + arrSize;
  1170. NewSys(p, size, isRealtime);
  1171. SetPC(p);
  1172. ELSE
  1173. arrayBlockSize := BlockHeaderSize + SIZEOF(ArrayBlockDesc);
  1174. INC(arrayBlockSize, (-arrayBlockSize) MOD ArrayAlignment); (* do. *)
  1175. blockSize := arrayBlockSize + BlockHeaderSize + (arrayDataOffset + arrSize);
  1176. INC(blockSize, (-blockSize) MOD BlockSize); (* round up to multiple of BlockSize *)
  1177. Machine.Acquire(Machine.Heaps);
  1178. arrayBlockAdr := NewBlock(blockSize);
  1179. IF arrayBlockAdr # 0 THEN
  1180. arrayBlock := arrayBlockAdr;
  1181. dataBlockAdr := arrayBlockAdr + arrayBlockSize (* - BlockHeaderSize + BlockHeaderSize *);
  1182. dataBlock := dataBlockAdr;
  1183. arrayBlock.typeDesc := arrayBlockTag;
  1184. dataBlock.typeDesc := elemType;
  1185. dataBlock.heapBlock := arrayBlock;
  1186. arrayBlock.mark := currentMarkValue;
  1187. arrayBlock.dataAdr := dataBlockAdr;
  1188. arrayBlock.size := blockSize;
  1189. (*! disable realtime block handling for the time being
  1190. IF isRealtime THEN
  1191. arrayBlock.nextRealtime := realtimeList;
  1192. realtimeList := arrayBlock
  1193. ELSE
  1194. arrayBlock.nextRealtime := NIL
  1195. END;
  1196. *)
  1197. (* clear data part of array here, since size parameter of Machine.Fill32 must be a multiple of 4. Some fields of the data part are filled below for GC. , *)
  1198. fillSize := blockSize - arrayBlockSize - BlockHeaderSize;
  1199. Machine.Fill32(dataBlockAdr, fillSize, 0); (* clear everything from dataBlockAdr until end of block *)
  1200. firstElem := dataBlockAdr + arrayDataOffset;
  1201. dataBlock.numElems := numElems;
  1202. dataBlock.current := NIL;
  1203. dataBlock.first := firstElem;
  1204. SetPC(dataBlock);
  1205. p := dataBlock;
  1206. ELSE
  1207. p := NIL
  1208. END;
  1209. IF allocationLogger # NIL THEN allocationLogger(p) END;
  1210. Machine.Release(Machine.Heaps)
  1211. END
  1212. END
  1213. END NewArr;
  1214. (* obsolete for generic object file / required only for old loader *)
  1215. PROCEDURE FillStaticType*(VAR staticTypeAddr: ADDRESS; startAddr, typeInfoAdr: ADDRESS; size, recSize: SIZE;
  1216. numPtrs, numSlots: LONGINT);
  1217. VAR p, offset: ADDRESS; staticTypeBlock {UNTRACED}: StaticTypeBlock;
  1218. BEGIN
  1219. Machine.Acquire(Machine.Heaps);
  1220. Machine.Fill32(startAddr, size, 0); (* clear whole static type, size MOD AddressSize = 0 implicitly, see WriteType in PCOF.Mod *)
  1221. SYSTEM.PUT(startAddr, MethodEndMarker); (* sentinel *)
  1222. (* methods and tags filled in later *)
  1223. offset := AddressSize * (numSlots + 1 + 1); (* #methods, max. no. of tags, method end marker (sentinel), pointer to type information*)
  1224. p := startAddr + offset;
  1225. SYSTEM.PUT(p + TypeDescOffset, typeInfoAdr); (* pointer to typeInfo *)
  1226. staticTypeBlock := SYSTEM.VAL(StaticTypeBlock, p);
  1227. staticTypeBlock.recSize := recSize;
  1228. staticTypeAddr := p;
  1229. (* create the pointer for the dynamic array of pointer offsets, the dynamic array of pointer offsets is stored in the static type
  1230. descriptor, it has no header part *)
  1231. INC(p, SIZEOF(StaticTypeDesc));
  1232. IF p MOD (2 * AddressSize) # 0 THEN INC(p, AddressSize) END;
  1233. SYSTEM.PUT(p + 3 * AddressSize, numPtrs); (* internal structure of dynamic array without pointers: the first 3 fields are unused *)
  1234. staticTypeBlock.pointerOffsets := SYSTEM.VAL(PointerOffsets, p); (* the fourth field contains the dimension of the array *)
  1235. (* pointer offsets filled in later *)
  1236. Machine.Release(Machine.Heaps)
  1237. END FillStaticType;
  1238. PROCEDURE AddFinalizer*(obj: ANY; n: FinalizerNode);
  1239. BEGIN
  1240. n.objWeak := obj; n.objStrong := NIL; n.finalizerStrong := NIL;
  1241. Machine.Acquire(Machine.Heaps);
  1242. n.nextFin := checkRoot; checkRoot := n;
  1243. IF Stats THEN INC(NfinalizeAlive) END;
  1244. Machine.Release(Machine.Heaps)
  1245. END AddFinalizer;
  1246. (** Compute total heap size, free space and largest free block size in bytes. This is a slow operation. *)
  1247. PROCEDURE GetHeapInfo*(VAR total, free, largest: SIZE);
  1248. VAR memBlock {UNTRACED}: Machine.MemoryBlock; blockAdr: ADDRESS;
  1249. block {UNTRACED}: HeapBlock;
  1250. BEGIN
  1251. Machine.Acquire(Machine.Heaps);
  1252. memBlock := Machine.memBlockHead;
  1253. total := 0; free := 0; largest := 0;
  1254. WHILE memBlock # NIL DO
  1255. total := total + memBlock.endBlockAdr - memBlock.beginBlockAdr;
  1256. blockAdr := memBlock.beginBlockAdr;
  1257. WHILE blockAdr < memBlock.endBlockAdr DO
  1258. block := SYSTEM.VAL(HeapBlock, blockAdr + BlockHeaderSize); (* get heap block *)
  1259. IF (block.mark < currentMarkValue) THEN (* free/unused block encountered *)
  1260. free := free + block.size;
  1261. IF ADDRESS(block.size) > ADDRESS(largest) THEN largest := block.size END
  1262. END;
  1263. blockAdr := blockAdr + block.size;
  1264. END;
  1265. memBlock := memBlock.next
  1266. END;
  1267. Machine.Release(Machine.Heaps)
  1268. END GetHeapInfo;
  1269. (* NilGC - Default garbage collector. *)
  1270. PROCEDURE NilGC;
  1271. BEGIN
  1272. HALT(301) (* garbage collector not available yet *)
  1273. END NilGC;
  1274. (* Init - Initialize the heap. *)
  1275. PROCEDURE Init;
  1276. VAR beginBlockAdr, endBlockAdr, freeBlockAdr, p: ADDRESS;
  1277. heapBlock: HeapBlockU; freeBlock: FreeBlockU; memBlock {UNTRACED}: Machine.MemoryBlock;
  1278. s: ARRAY 32 OF CHAR; minSize,i: LONGINT;
  1279. BEGIN
  1280. Machine.GetConfig("EnableFreeLists", s);
  1281. EnableFreeLists := (s[0] = "1");
  1282. Machine.GetConfig("EnableReturnBlocks", s);
  1283. EnableReturnBlocks := (s[0] = "1");
  1284. IF EnableReturnBlocks THEN Trace.String("Heaps:ReturnBlocks enabled"); Trace.Ln END;
  1285. Machine.GetConfig("TraceHeaps",s);
  1286. trace := (s[0] = "1");
  1287. minSize := 32;
  1288. FOR i := 0 TO MaxFreeLists DO
  1289. freeLists[i].minSize := minSize;
  1290. freeLists[i].first := NIL; freeLists[i].last := NIL;
  1291. IF i < FreeListBarrier THEN INC( minSize, BlockSize ) ELSE minSize := 2 * minSize END
  1292. END;
  1293. GC := NilGC;
  1294. newSum := 0;
  1295. checkRoot := NIL; finalizeRoot := NIL; rootList := NIL; realtimeList := NIL;
  1296. gcStatus := NIL;
  1297. Machine.SetGCParams;
  1298. Machine.GetStaticHeap(beginBlockAdr, endBlockAdr, freeBlockAdr);
  1299. (* the Type desciptor is generated by the compiler, therefore the linker does not have to patch anything any more *)
  1300. freeBlockTag := SYSTEM.TYPECODE (FreeBlockDesc);
  1301. systemBlockTag := SYSTEM.TYPECODE (SystemBlockDesc);
  1302. recordBlockTag := SYSTEM.TYPECODE (RecordBlockDesc);
  1303. protRecBlockTag := SYSTEM.TYPECODE (ProtRecBlockDesc);
  1304. arrayBlockTag := SYSTEM.TYPECODE (ArrayBlockDesc);
  1305. (* find last block in static heap *)
  1306. p := beginBlockAdr;
  1307. heapBlock := SYSTEM.VAL(HeapBlock, p + BlockHeaderSize);
  1308. WHILE p < freeBlockAdr DO
  1309. initBlock := SYSTEM.VAL(ANY, heapBlock.dataAdr);
  1310. p := p + heapBlock.size;
  1311. heapBlock := SYSTEM.VAL(HeapBlock, p + BlockHeaderSize)
  1312. END;
  1313. ASSERT(p = freeBlockAdr);
  1314. IF endBlockAdr - freeBlockAdr > 0 THEN
  1315. (* initialization of free heap block done here since boot file is only written up to freeBlockAdr *)
  1316. freeBlock := freeBlockAdr + BlockHeaderSize;
  1317. InitFreeBlock(freeBlock, Unmarked, NilVal, endBlockAdr - freeBlockAdr);
  1318. IF EnableFreeLists THEN AppendFreeBlock(freeBlock) END;
  1319. ASSERT(freeBlock.size MOD BlockSize = 0)
  1320. END;
  1321. currentMarkValue := 1;
  1322. (* extend the heap for one block such that module initialization can continue as long as Heaps.GC is not set validly *)
  1323. Machine.ExpandHeap(1, 1, memBlock, beginBlockAdr, endBlockAdr); (* try = 1, size = 1 -> the minimal heap block expansion is performed *)
  1324. IF endBlockAdr > beginBlockAdr THEN
  1325. freeBlock := beginBlockAdr + BlockHeaderSize;
  1326. InitFreeBlock(freeBlock, Unmarked, NilVal, endBlockAdr - beginBlockAdr);
  1327. Machine.SetMemoryBlockEndAddress(memBlock, endBlockAdr);
  1328. IF EnableFreeLists THEN AppendFreeBlock(freeBlock) END;
  1329. sweepMarkValue := currentMarkValue;
  1330. sweepMemBlock := memBlock;
  1331. sweepBlockAdr := beginBlockAdr
  1332. END;
  1333. END Init;
  1334. PROCEDURE SetHeuristic*;
  1335. BEGIN
  1336. GCType := HeuristicStackInspectionGC;
  1337. Trace.String("GC mode : heuristic"); Trace.Ln;
  1338. END SetHeuristic;
  1339. PROCEDURE SetMetaData*;
  1340. BEGIN
  1341. GCType := MetaDataForStackGC;
  1342. Trace.String("GC mode : metadata"); Trace.Ln;
  1343. END SetMetaData;
  1344. BEGIN
  1345. (* The meta data stack inspection is more efficient than the heuristics *)
  1346. GCType := HeuristicStackInspectionGC;
  1347. Init;
  1348. END Heaps.
  1349. (*
  1350. TraceHeap:
  1351. 0 1 NR NEW record
  1352. 1 2 NA/NV NEW array
  1353. 2 4 NS SYSTEM.NEW
  1354. 3 8 DR deallocate record #
  1355. 4 16 DA deallocate array #
  1356. 5 32 DS deallocate sysblk #
  1357. 6 64 NT NewType
  1358. 7 128
  1359. 8 256 FB show free blocks #
  1360. 9 512 DP deallocate protrec #
  1361. 10 1024 finalizers
  1362. 11 2048 live/dead #
  1363. 12 4096 trace mark stack overflows #
  1364. # influences timing
  1365. *)
  1366. (*
  1367. 20.03.1998 pjm Started
  1368. 17.08.1998 pjm FindRoots method
  1369. 18.08.1998 pjm findPossibleRoots removed, use FindRoots method
  1370. 09.10.1998 pjm NewRec with page alignment
  1371. 21.01.1999 pjm Mark adapted for AosBuffers
  1372. 26.01.1999 pjm Incorporated changes for new compiler
  1373. 10.11.2000 pjm Finalizers
  1374. 26.01.2001 pjm Removed trapReserve, reimplemented NewBlock
  1375. 11.11.2004 lb Garbage collector with marking stack
  1376. 19.06.2007 ug Garbage collector using meta data for stack inspection (cf. Objects)
  1377. 11.07.2008 ug new heap data structures and adaption to GC
  1378. *)
  1379. Compiler.Compile -p=Win32G --traceModule=Trace Heaps.Mod ~
  1380. StaticLinker.Link --fileFormat=PE32 --fileName=A2M.exe --extension=GofW --displacement=401000H Runtime Trace Kernel32 Machine Heaps Modules Objects Kernel KernelLog Streams Commands FIles WinFS Clock Dates Reals Strings Diagnostics BitSets StringPool ObjectFile GenericLinker Reflection GenericLoader BootConsole ~
  1381. FSTools.CloseFiles A2M.exe ~
  1382. FoxBinarySymbolFile.Test /temp/obj/Heaps ~