Heaps.Mod 54 KB

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