Heaps.Mod 57 KB

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