Heaps.Mod 70 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145
  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 Builtins (* enforce import order *), SYSTEM, Trace, Machine;
  11. CONST
  12. EnableRefCount =TRUE;
  13. Paranoid = TRUE; (* if paranoid =true, then during mark phase the GC can accept spurious pointers but reports them
  14. paranoid = false expects correct metadata and correct settings of untraced variables
  15. moreover, it should improve GC mark speed *)
  16. DebugValue = LONGINT(0DEADDEADH); (* set non-0 to clear free storage to this value *)
  17. Stats* = TRUE; (* maintain statistical counters *)
  18. AddressSize = SIZEOF(ADDRESS);
  19. MaxTries = 16; (* max number of times to try and allocate memory, before trapping *)
  20. Unmarked = 0; (* mark value of free blocks *)
  21. BlockSize* = 8*SIZEOF(ADDRESS); (* power of two, <= 32 for RegisterCandidates. Must be large enough to accomodate any basic block *)
  22. ArrayAlignment = 8; (* first array element of ArrayBlock and first data element of SystemBlock must be aligned to 0 MOD ArrayAlignment *)
  23. BlockHeaderSize* = 2 * AddressSize;
  24. HeapBlockOffset* = - 2 * AddressSize;
  25. TypeDescOffset* = - AddressSize;
  26. MaxCandidates = 1024;
  27. ProtTypeBit* = 31; (** flags in TypeDesc, RoundUp(log2(MaxTags)) low bits reserved for extLevel *)
  28. FlagsOfs = AddressSize * 3; (* flags offset in TypeDesc *)
  29. ModOfs* = AddressSize * 4; (* moduleAdr offset in TypeDesc *)
  30. TypeNameOfs = AddressSize * 5; (* type name offset in TypeDesc *)
  31. ModNameOfs = AddressSize * 2; (* module name offset in ModuleDesc *)
  32. MinPtrOfs = -40000000H; (* sentinel offset for ptrOfs *)
  33. MethodEndMarker* = MinPtrOfs; (* marks the end of the method addresses, used in Info.ModuleDetails *)
  34. NilVal* = 0;
  35. NumPriorities* = 6;
  36. HeuristicStackInspectionGC* = 0;
  37. MetaDataForStackGC* = 1;
  38. (* generations *)
  39. Old = 1;
  40. Young = 0;
  41. GenerationMask = 2;
  42. (* card set for generational GC *)
  43. CardSize = 4096;
  44. SetSize=SIZEOF(SET) * 8;
  45. TYPE
  46. RootObject* = OBJECT (* ref. Linker0 *)
  47. VAR nextRoot: RootObject; (* for linking root objects during GC *)
  48. PROCEDURE FindRoots*; (** abstract *)
  49. BEGIN HALT(301) END FindRoots;
  50. END RootObject;
  51. ProcessLink* = OBJECT (RootObject)
  52. VAR next*, prev*: ProcessLink
  53. END ProcessLink;
  54. ProcessQueue* = RECORD
  55. head*, tail*: ProcessLink
  56. END;
  57. Finalizer* = PROCEDURE {DELEGATE} (obj: ANY);
  58. FinalizerNode* = POINTER TO RECORD
  59. objWeak* {UNTRACED}: ANY; (* weak reference to checked object *)
  60. nextFin: FinalizerNode; (* in finalization list *)
  61. objStrong*: ANY; (* strong reference to object to be finalized *)
  62. finalizer* {UNTRACED} : Finalizer;(* finalizer, if any. Untraced for the case that a finalizer points to objWeak *)
  63. finalizerStrong: Finalizer; (* strong reference to the object that is referenced by the finalizer, if any *)
  64. END;
  65. HeapBlock* = POINTER TO HeapBlockDesc; (* base object of all heap blocks *)
  66. HeapBlockU = POINTER {UNSAFE,UNTRACED} TO HeapBlockDesc; (* base object of all heap blocks *)
  67. HeapBlockDesc* = RECORD
  68. heapBlock {FICTIVE =HeapBlockOffset}: ADDRESS;
  69. typeDesc {FICTIVE =TypeDescOffset}: POINTER {UNSAFE,UNTRACED} TO StaticTypeDesc;
  70. (* when this is changed --> change constant in Machine too and provide changes in FoxIntermediateBackend where noted *)
  71. mark: WORD;
  72. refCount: WORD;
  73. dataAdr-: ADDRESS;
  74. size-: SIZE;
  75. nextMark {UNTRACED}: HeapBlock;
  76. END;
  77. (* mechanism of the generational garbage collector
  78. - newly created objects belong to the young generation
  79. - a new link from old to young must be entered in a list (an array), when the list is (nearly) full a GC cycle must be run
  80. - any other link, from young to young or from rootset to young does not require action
  81. - a gc cycle dealing with the young objects traverses the root set and the set of young pointers
  82. - older objects are not marked or traversed
  83. - when sweeping only unmarked objects not older than the sweep generation can be freed
  84. - objects that survive a collection are considered old and are always moved to the tenured objects
  85. *)
  86. FreeBlock* = POINTER TO FreeBlockDesc;
  87. FreeBlockU = POINTER {UNSAFE,UNTRACED} TO FreeBlockDesc;
  88. FreeBlockDesc* = RECORD (HeapBlockDesc)
  89. next{UNTRACED}: FreeBlock;
  90. END;
  91. SystemBlock* = POINTER TO SystemBlockDesc;
  92. SystemBlockDesc = RECORD (HeapBlockDesc)
  93. END;
  94. RecordBlock* = POINTER TO RecordBlockDesc;
  95. RecordBlockU = POINTER {UNSAFE,UNTRACED} TO RecordBlockDesc;
  96. RecordBlockDesc = RECORD (HeapBlockDesc)
  97. END;
  98. ProtRecBlock* = POINTER TO ProtRecBlockDesc;
  99. ProtRecBlockU = POINTER {UNSAFE,UNTRACED} TO ProtRecBlockDesc;
  100. ProtRecBlockDesc* = RECORD (RecordBlockDesc)
  101. count*: LONGINT;
  102. locked*: BOOLEAN;
  103. awaitingLock*, awaitingCond*: ProcessQueue;
  104. lockedBy*: ANY;
  105. waitingPriorities*: ARRAY NumPriorities OF LONGINT;
  106. lock*: ANY; (* generic implementation slot -- used by LinuxAos *)
  107. END;
  108. ArrayBlock* = POINTER TO ArrayBlockDesc;
  109. ArrayBlockU = POINTER {UNSAFE,UNTRACED} TO ArrayBlockDesc;
  110. ArrayBlockDesc = RECORD (HeapBlockDesc)
  111. END;
  112. TypeInfo*= POINTER{UNSAFE,UNTRACED} TO TypeInfoDesc;
  113. TypeInfoDesc = RECORD
  114. descSize: SIZE;
  115. sentinel: ADDRESS; (* = MPO-4 *)
  116. tag: ADDRESS; (* pointer to static type descriptor, only used by linker and loader *)
  117. flags: SET;
  118. mod: ADDRESS; (* module *)
  119. name*: ARRAY 32 OF CHAR;
  120. END;
  121. StaticTypeBlock*= POINTER TO StaticTypeDesc;
  122. StaticTypeBlockU= POINTER {UNSAFE,UNTRACED} TO StaticTypeDesc;
  123. StaticTypeDesc = RECORD
  124. info {FICTIVE =TypeDescOffset}: TypeInfo;
  125. recSize: SIZE;
  126. pointerOffsets* {UNTRACED}: PointerOffsets;
  127. END;
  128. PointerOffsets = POINTER TO ARRAY OF SIZE;
  129. Block*= POINTER {UNSAFE,UNTRACED} TO RECORD
  130. heapBlock {FICTIVE =HeapBlockOffset}: HeapBlock;
  131. typeBlock {FICTIVE =TypeDescOffset}: StaticTypeBlock;
  132. END;
  133. DataBlockU = POINTER {UNSAFE,UNTRACED} TO DataBlockDesc;
  134. DataBlockDesc*= RECORD
  135. heapBlock {FICTIVE =HeapBlockOffset}: POINTER {UNSAFE,UNTRACED} TO HeapBlockDesc;
  136. typeDesc {FICTIVE =TypeDescOffset}: POINTER {UNSAFE,UNTRACED} TO StaticTypeDesc;
  137. END;
  138. ArrayDataBlockU = POINTER {UNSAFE,UNTRACED} TO ArrayDataBlockDesc;
  139. ArrayDataBlockDesc*= RECORD (DataBlockDesc)
  140. numElems: SIZE;
  141. current: ADDRESS; (* unused *)
  142. first: ADDRESS;
  143. (* len info *)
  144. (* data *)
  145. END;
  146. (*StackBlock = POINTER{UNSAFE} TO StackBlockDesc;
  147. StackBlockDesc= RECORD
  148. link: StackBlock;
  149. pc: ADDRESS;
  150. END;
  151. *)
  152. (* a single pointer -- required as base type TD for array of pointer
  153. Don't rename this. Compiler refers to this TD by name
  154. *)
  155. AnyPtr = RECORD a: ANY END;
  156. TYPE
  157. GCStatus* = OBJECT
  158. (* the following procedures are overridden in Objects.GCStatusExt. The reason is that shared objects can only be implemented in modules Objects or higher *)
  159. PROCEDURE SetgcOngoing*(value: BOOLEAN);
  160. BEGIN
  161. HALT(2000);
  162. END SetgcOngoing;
  163. PROCEDURE GetgcOngoing*(): BOOLEAN;
  164. BEGIN
  165. HALT(2001); RETURN FALSE
  166. END GetgcOngoing;
  167. PROCEDURE WaitForGCEnd*;
  168. BEGIN
  169. HALT(2002)
  170. END WaitForGCEnd;
  171. END GCStatus;
  172. CONST
  173. MaxFreeLists = 20;
  174. FreeListBarrier = 7;
  175. TYPE
  176. FreeList= RECORD minSize: SIZE; first {UNTRACED}, last{UNTRACED}: FreeBlock END;
  177. FreeLists = ARRAY MaxFreeLists+1 OF FreeList;
  178. MarkList = RECORD first{UNTRACED}, last{UNTRACED}: HeapBlock END;
  179. VAR
  180. markList: MarkList;
  181. freeLists: FreeLists;
  182. GC*: PROCEDURE; (** activate the garbage collector *)
  183. initBlock {UNTRACED}: ANY; (* anchor for init calls *)
  184. currentMarkValue: LONGINT; (* all objects that have this value in their mark field are still used - initial value filled in by linker *)
  185. generationMarkValues : ARRAY 2 OF LONGINT; (* mark values of the generations *)
  186. currentGeneration: LONGINT; (* current global generation state *)
  187. sweepMarkValue: LONGINT; (* most recent mark value *)
  188. sweepBlockAdr: ADDRESS; (* where to resume sweeping *)
  189. sweepMemBlock {UNTRACED}: Machine.MemoryBlock; (* where to resume sweeping *)
  190. candidates: ARRAY MaxCandidates OF ADDRESS; (* procedure stack pointer candidates *)
  191. numCandidates: LONGINT;
  192. rootList {UNTRACED}: RootObject; (* list of root objects during GC - tracing does not harm but is unnecessary *)
  193. realtimeList {UNTRACED}: HeapBlock; (* list of realtime objects - tracing does not harm but is unnecessary *)
  194. newSum: SIZE;
  195. checkRoot: FinalizerNode; (* list of checked objects (contains weak references to the checked objects) *)
  196. finalizeRoot: FinalizerNode; (* objects scheduled for finalization (contains references to scheduled objects) *)
  197. freeBlockTag, systemBlockTag, recordBlockTag, protRecBlockTag, arrayBlockTag: ADDRESS; (* same values of type ADDRESS *)
  198. (** Statistics. Will only be maintained if Stats = TRUE *)
  199. (** Memory allocation statistics *)
  200. Nnew- : LONGINT; (** Number of times NewBlock has been called since system startup *)
  201. NnewBytes- : HUGEINT; (** Number of bytes allocated by NewBlock since system startup *)
  202. (** Garbage collection statistics *)
  203. Ngc- : LONGINT; (** Number of GC cycles since system startup *)
  204. (** Statistics considering the last GC cyle *)
  205. Nmark-, Nmarked-, NfinalizeAlive-, NfinalizeDead-: LONGINT;
  206. NgcCyclesMark-, NgcCyclesLastRun-, NgcCyclesMax-, NgcCyclesAllRuns- : HUGEINT;
  207. NgcSweeps-, NgcSweepTime-, NgcSweepMax-: HUGEINT;
  208. gcStatus*: GCStatus;
  209. GCType*: LONGINT;
  210. freeBlockFound-, freeBlockNotFound-: LONGINT;
  211. EnableFreeLists, EnableReturnBlocks, trace-: BOOLEAN;
  212. allocationLogger-: PROCEDURE(p: ANY);
  213. VAR resets, refers, assigns: SIZE;
  214. (* for low level debugging of allocation -- beware: errors or traps in allocation logger can produce catastrophy - loggers may not allocate memory *)
  215. PROCEDURE SetAllocationLogger*(a: PROCEDURE (p:ANY));
  216. BEGIN
  217. allocationLogger := a
  218. END SetAllocationLogger;
  219. (* check validity of p *)
  220. PROCEDURE CheckPointer(p: ADDRESS): BOOLEAN;
  221. VAR
  222. tdAdr: ADDRESS;
  223. block: Block;
  224. BEGIN
  225. block := p;
  226. IF (block # NIL) & Machine.ValidHeapAddress(ADDRESS OF block.heapBlock)THEN
  227. block := block.heapBlock;
  228. IF (block = NIL) THEN RETURN TRUE (* block without heap header -- considered untraced *)
  229. ELSIF Machine.ValidHeapAddress(ADDRESS OF block.typeBlock) THEN
  230. tdAdr := block.typeBlock;
  231. IF (tdAdr = systemBlockTag) OR (tdAdr = recordBlockTag) OR (tdAdr = protRecBlockTag) OR (tdAdr = arrayBlockTag) THEN
  232. RETURN TRUE;
  233. ELSE
  234. Trace.Memory(p-64, 128);
  235. HALT(103);
  236. END
  237. ELSE HALT(102);
  238. END
  239. ELSE HALT(101);
  240. END;
  241. Trace.String("Heaps: invalid pointer encountered: "); Trace.Address(p); Trace.String(","); Trace.Address(block); Trace.Ln;
  242. HALT(100);
  243. RETURN FALSE
  244. END CheckPointer;
  245. PROCEDURE AppendToMarkList(heapBlock: HeapBlockU);
  246. BEGIN
  247. IF markList.first = NIL THEN
  248. markList.first := heapBlock
  249. ELSE
  250. markList.last.nextMark := heapBlock
  251. END;
  252. markList.last := heapBlock;
  253. heapBlock.nextMark := NIL; (* sanity of the list *)
  254. END AppendToMarkList;
  255. PROCEDURE ExtractFromMarkList(): HeapBlockU;
  256. VAR heapBlock: HeapBlockU;
  257. BEGIN
  258. heapBlock := markList.first;
  259. IF heapBlock # NIL THEN
  260. markList.first := heapBlock.nextMark;
  261. (* by the construction of AppendToMarkList, it is not necessary to update the last pointer *)
  262. END;
  263. RETURN heapBlock;
  264. END ExtractFromMarkList;
  265. VAR
  266. cardSet: ARRAY 0x100000000 DIV SetSize DIV CardSize OF SET; (* 1 k blocks *)
  267. PROCEDURE ShowCards*;
  268. VAR i: LONGINT;
  269. BEGIN
  270. FOR i := 0 TO LEN(cardSet)-1 DO
  271. IF cardSet[i] # {} THEN
  272. Trace.Int(i,1); Trace.Set(cardSet[i]); Trace.Ln;
  273. END;
  274. END;
  275. END ShowCards;
  276. PROCEDURE ClearCardSet;
  277. VAR i: LONGINT;
  278. BEGIN
  279. HALT(100);
  280. FOR i := 0 TO LEN(cardSet)-1 DO
  281. cardSet[i] := {};
  282. END;
  283. END ClearCardSet;
  284. (* lock-free entry into card-set *)
  285. PROCEDURE EnterInCardSet(adr: ADDRESS);
  286. VAR value: SET;
  287. BEGIN
  288. HALT(100);
  289. adr := adr DIV CardSize;
  290. IF adr MOD SetSize IN CAS(cardSet[adr DIV SetSize],{},{}) THEN
  291. RETURN
  292. ELSE
  293. LOOP
  294. value := CAS (cardSet[adr DIV SetSize], {},{});
  295. IF CAS (cardSet[adr DIV SetSize], value, value + {adr MOD SetSize}) = value THEN EXIT END;
  296. (*CPU.Backoff;*)
  297. END;
  298. END;
  299. END EnterInCardSet;
  300. (* Sweep phase *)
  301. PROCEDURE SweepCardSet();
  302. VAR
  303. block : HeapBlockU ;
  304. blockMark, blockGeneration: LONGINT;
  305. memBlock {UNTRACED} : Machine.MemoryBlock;
  306. blockAdr,a1,a2: ADDRESS;
  307. count,count2,count3: LONGINT;
  308. orgBlock: HeapBlockU;
  309. mark: BOOLEAN;
  310. time1, time2: HUGEINT;
  311. BEGIN {UNCHECKED}
  312. HALT(100);
  313. (* blocks in the bootheap are not found by the sweep card set! *)
  314. time1 := Machine.GetTimer ();
  315. count := 0; count2 := 0;
  316. memBlock := Machine.memBlockHead;
  317. WHILE (memBlock # NIL) DO
  318. blockAdr := memBlock.beginBlockAdr;
  319. WHILE (blockAdr < memBlock.endBlockAdr) DO
  320. block := blockAdr + BlockHeaderSize;
  321. a1 := blockAdr DIV CardSize;
  322. a2 := (blockAdr + block.size) DIV CardSize;
  323. mark := FALSE;
  324. REPEAT
  325. mark := a1 MOD SetSize IN cardSet[a1 DIV SetSize];
  326. INC(a1);
  327. UNTIL mark OR (a1 > a2);
  328. IF mark THEN
  329. IF (block.mark MOD GenerationMask = Old) & (block.mark >= generationMarkValues[Old]) THEN
  330. orgBlock := block.dataAdr;
  331. ASSERT(orgBlock # NIL);
  332. Inspect(orgBlock, Old);
  333. INC(count);
  334. ELSE INC(count2);
  335. END;
  336. ELSE
  337. INC(count3);
  338. END;
  339. blockAdr := blockAdr + block.size
  340. END;
  341. memBlock := memBlock.next;
  342. END;
  343. time2 := Machine.GetTimer ();
  344. (*
  345. TRACE(LONGINT((time2-time1) DIV (1024*1024)));
  346. TRACE(count,count2,count3);
  347. *)
  348. END SweepCardSet;
  349. PROCEDURE Inspect(block {UNTRACED}: ANY; generation: LONGINT);
  350. VAR
  351. heapBlock {UNTRACED}: HeapBlock;
  352. rootObj{UNTRACED}: RootObject;
  353. blockMeta : Block;
  354. BEGIN
  355. (* 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 *)
  356. IF (block = NIL) OR Paranoid & ~CheckPointer(block) THEN RETURN END;
  357. blockMeta := block;
  358. heapBlock := blockMeta.heapBlock;
  359. IF (heapBlock = NIL)
  360. OR (heapBlock.mark >= currentMarkValue) OR (heapBlock.mark MOD GenerationMask > generation) & ~((blockMeta.typeBlock#NIL) & (block IS RootObject)) THEN RETURN END;
  361. (* blocks in the bootheap are not found by the sweep card set, thus the root objects must be traversed in all cases *)
  362. heapBlock.mark := currentMarkValue + Old (* surviving objects age *);
  363. IF Stats THEN INC(Nmarked) END;
  364. IF (heapBlock IS RecordBlock) OR (heapBlock IS ProtRecBlock) OR (heapBlock IS ArrayBlock) THEN
  365. IF block IS RootObject THEN
  366. rootObj := block(RootObject);
  367. rootObj.nextRoot := rootList; rootList := rootObj; (* link root list *)
  368. END;
  369. IF (LEN(blockMeta.typeBlock.pointerOffsets) > 0) OR (heapBlock IS ProtRecBlock) THEN (* not atomic or heapBlock is ProtRecBlock containing awaiting queues *)
  370. AppendToMarkList(heapBlock);
  371. END
  372. END
  373. END Inspect;
  374. (** Mark - Mark an object and its decendents. Used by findRoots. *)
  375. PROCEDURE Mark*(p {UNTRACED}: ANY);
  376. VAR orgBlock: ADDRESS; staticTypeBlock {UNTRACED}: StaticTypeBlock;
  377. orgHeapBlock {UNTRACED}: HeapBlock;
  378. currentArrayElemAdr, lastArrayElemAdr: ADDRESS; i: LONGINT;
  379. protected {UNTRACED}: ProtRecBlock;
  380. b {UNTRACED}: POINTER {UNSAFE} TO RECORD p: ANY END;
  381. meta {UNTRACED }: POINTER {UNSAFE} TO RECORD staticTypeBlock {FICTIVE=TypeDescOffset}: StaticTypeBlock; last, current, first: ADDRESS END;
  382. BEGIN{UNCHECKED} (* omit any range checks etc.*)
  383. IF Stats THEN INC(Nmark) END;
  384. Inspect(p,currentGeneration);
  385. orgHeapBlock := ExtractFromMarkList();
  386. WHILE orgHeapBlock # NIL DO
  387. orgBlock := orgHeapBlock.dataAdr;
  388. meta := orgBlock;
  389. staticTypeBlock := meta.staticTypeBlock;
  390. IF ~(orgHeapBlock IS ArrayBlock) THEN
  391. FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
  392. b := orgBlock + staticTypeBlock.pointerOffsets[i];
  393. Inspect(b.p,currentGeneration)
  394. END
  395. ELSE
  396. currentArrayElemAdr := meta.first;
  397. lastArrayElemAdr := meta.first + meta.last * staticTypeBlock.recSize;
  398. WHILE currentArrayElemAdr < lastArrayElemAdr DO
  399. FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
  400. b := currentArrayElemAdr + staticTypeBlock.pointerOffsets[i];
  401. Inspect(b.p,currentGeneration)
  402. END;
  403. INC(currentArrayElemAdr, staticTypeBlock.recSize);
  404. END
  405. END;
  406. IF orgHeapBlock IS ProtRecBlock THEN
  407. protected := orgHeapBlock(ProtRecBlock);
  408. Inspect(protected.awaitingLock.head, currentGeneration);
  409. Inspect(protected.awaitingCond.head, currentGeneration);
  410. Inspect(protected.lockedBy, currentGeneration);
  411. Inspect(protected.lock, currentGeneration);
  412. END;
  413. orgHeapBlock := ExtractFromMarkList();
  414. END;
  415. END Mark;
  416. PROCEDURE MarkRealtimeObjects;
  417. VAR heapBlock {UNTRACED}: HeapBlock;
  418. BEGIN
  419. (*! disable realtime block handling for the time being
  420. first, we have to check that objects cannot move between mark list and realtime list
  421. heapBlock := realtimeList;
  422. WHILE heapBlock # NIL DO
  423. Mark(SYSTEM.VAL(ANY, heapBlock.dataAdr));
  424. heapBlock := heapBlock.nextRealtime;
  425. END;
  426. *)
  427. END MarkRealtimeObjects;
  428. (** WriteType - Write a type name (for tracing only). *)
  429. PROCEDURE WriteType*(t: ADDRESS); (* t is static type descriptor *)
  430. VAR m: ADDRESS; i: LONGINT; ch: CHAR;
  431. typeDesc: StaticTypeBlockU;
  432. BEGIN
  433. typeDesc := t;
  434. m := typeDesc.info.mod;
  435. IF m # NilVal THEN (* could be a type without module, e.g. a Java class *)
  436. i := 0; SYSTEM.GET (m + ModNameOfs + i, ch);
  437. WHILE (ch >= "0") & (ch <= "z") & (i # 32) DO
  438. Trace.Char(ch);
  439. INC(i); SYSTEM.GET (m + ModNameOfs + i, ch)
  440. END
  441. ELSE
  442. Trace.String("NIL")
  443. END;
  444. Trace.Char(".");
  445. IF typeDesc.info.name = "" THEN
  446. Trace.String("-")
  447. ELSE
  448. Trace.String(typeDesc.info.name);
  449. END;
  450. END WriteType;
  451. (** free list handling **)
  452. PROCEDURE ClearFreeLists;
  453. VAR i: LONGINT;
  454. BEGIN
  455. FOR i := 0 TO MaxFreeLists DO
  456. freeLists[i].first := NIL;
  457. freeLists[i].last := NIL
  458. END;
  459. END ClearFreeLists;
  460. (* insert element in fifo, first = freeList.first; last = freeList.last *)
  461. PROCEDURE AppendFree(VAR freeList: FreeList; block: FreeBlock);
  462. BEGIN
  463. ASSERT(block.size >= freeList.minSize);
  464. IF freeList.first = NIL THEN
  465. freeList.first := block; freeList.last := block
  466. ELSE
  467. freeList.last.next := block;
  468. freeList.last := block;
  469. END;
  470. block.next := NIL
  471. END AppendFree;
  472. (* get last element from fifo *)
  473. PROCEDURE GetFree(VAR freeList: FreeList): FreeBlockU;
  474. VAR block: FreeBlockU;
  475. BEGIN
  476. IF freeList.first = NIL THEN block := NIL;
  477. ELSIF freeList.first = freeList.last THEN block := freeList.first; freeList.first := NIL; freeList.last := NIL
  478. ELSE block := freeList.first; freeList.first := block.next; block.next := NIL
  479. END;
  480. RETURN block
  481. END GetFree;
  482. (** insert sorted into queue, no handling of last queue element *)
  483. PROCEDURE InsertSorted(VAR freeList: FreeList; block: FreeBlock);
  484. VAR x: FreeBlock;
  485. BEGIN
  486. (* keep them ordered to avoid unnecessary splits *)
  487. x := freeList.first;
  488. WHILE x # NIL DO
  489. ASSERT(x # block);
  490. x := x.next;
  491. END;
  492. x := freeList.first;
  493. IF (x = NIL) OR (block.size <= x.size) THEN
  494. block.next := x;
  495. freeList.first := block;
  496. ELSE
  497. WHILE (x.next # NIL) & (block.size > x.next.size) DO x := x.next END;
  498. block.next := x.next;
  499. x.next := block;
  500. END;
  501. END InsertSorted;
  502. PROCEDURE AppendFreeBlock(block: FreeBlock);
  503. VAR i: LONGINT;
  504. BEGIN
  505. i := MaxFreeLists;
  506. WHILE (i > 0) & (freeLists[i].minSize > block.size) DO DEC( i ) END;
  507. IF i < FreeListBarrier THEN
  508. AppendFree(freeLists[i], block);
  509. ELSE
  510. AppendFree(freeLists[i], block);
  511. (*
  512. keeping lists sorted has some positive impact on heap utilization
  513. but it slows down heap allocation speed:
  514. InsertSorted(freeLists[i], block);
  515. *)
  516. END;
  517. END AppendFreeBlock;
  518. PROCEDURE FindFreeBlock( size: SIZE ): FreeBlock;
  519. VAR prev, block: FreeBlock; i: LONGINT;
  520. BEGIN
  521. i := MaxFreeLists;
  522. WHILE (i > 0) & (freeLists[i].minSize > size) DO DEC( i ) END;
  523. REPEAT
  524. IF i < FreeListBarrier THEN
  525. block := GetFree(freeLists[i]);
  526. ELSE
  527. block := freeLists[i].first;
  528. prev := NIL;
  529. WHILE (block # NIL) & (block.size < size) DO
  530. prev := block;
  531. block := block.next;
  532. END;
  533. IF block # NIL THEN (* blockize >= size *)
  534. IF prev = NIL THEN
  535. freeLists[i].first := block.next;
  536. ELSE prev.next := block.next
  537. END;
  538. IF block = freeLists[i].last THEN
  539. freeLists[i].last := prev
  540. END;
  541. block.next := NIL;
  542. END;
  543. (*
  544. prev := freeLists[i].first;
  545. WHILE prev # NIL DO
  546. ASSERT(prev # block);
  547. prev := prev.next;
  548. END;
  549. *)
  550. END;
  551. INC( i )
  552. UNTIL (block # NIL) OR (i > MaxFreeLists);
  553. RETURN block
  554. END FindFreeBlock;
  555. PROCEDURE GetFreeBlockAndSplit(size: SIZE): FreeBlock;
  556. VAR p,remainder: FreeBlockU; adr: ADDRESS;
  557. BEGIN
  558. p := FindFreeBlock(size);
  559. 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 *)
  560. ASSERT(ADDRESS(p.size - size) >= BlockHeaderSize + SIZEOF(FreeBlockDesc));
  561. adr := p;
  562. remainder := adr + size;
  563. InitFreeBlock(remainder, Unmarked, NilVal, p.size - size);
  564. AppendFreeBlock(remainder);
  565. p.size := size;
  566. END;
  567. IF p # NIL THEN INC(freeBlockFound) ELSE INC(freeBlockNotFound) END;
  568. RETURN p
  569. END GetFreeBlockAndSplit;
  570. PROCEDURE GetFreeBlock(size: SIZE; VAR p: FreeBlock);
  571. BEGIN
  572. IF EnableFreeLists THEN
  573. IF sweepMarkValue < currentMarkValue THEN
  574. (*Trace.String("clear free lists and lazy sweep"); Trace.Ln;*)
  575. ClearFreeLists;
  576. LazySweep(MAX(SIZE), p)
  577. END;
  578. p := GetFreeBlockAndSplit(size)
  579. ELSE
  580. LazySweep(size, p)
  581. END;
  582. IF size # MAX(SIZE) THEN
  583. INC(throughput, size);
  584. END;
  585. END GetFreeBlock;
  586. (* Sweep phase *)
  587. PROCEDURE LazySweep(size: ADDRESS; VAR p {UNTRACED}: FreeBlock);
  588. VAR
  589. lastFreeBlockAdr: ADDRESS;
  590. lastFreeBlockSize: ADDRESS;
  591. block : HeapBlockU ; freeBlock, lastFreeBlock: FreeBlockU;
  592. blockMark, blockGeneration, refCount: LONGINT; blockSize: SIZE;
  593. time1, time2: HUGEINT;
  594. CONST FreeBlockHeaderSize = SIZEOF(FreeBlockDesc) + BlockHeaderSize;
  595. CONST StrongChecks = FALSE;
  596. BEGIN{UNCHECKED}
  597. INC(NgcSweeps);
  598. time1 := Machine.GetTimer();
  599. ASSERT(~EnableFreeLists OR (size = MAX(SIZE)));
  600. lastFreeBlockAdr := NilVal;
  601. lastFreeBlock := NIL;
  602. IF (sweepMemBlock = NIL) (* OR (sweepMarkValue < currentMarkValue)*) THEN (* restart lazy sweep including clearance of lists *)
  603. (* note that the order of the blocks does not necessarily represent the historical order of insertion
  604. as they are potentially provided by the underlying host system in with non-increasing address ranges
  605. blocks are sorted by Machine.Mod in an increased address range order
  606. *)
  607. sweepMemBlock := Machine.memBlockHead;
  608. sweepBlockAdr := Machine.memBlockHead.beginBlockAdr;
  609. sweepMarkValue := currentMarkValue;
  610. END;
  611. WHILE (sweepMemBlock # NIL) DO
  612. WHILE (sweepBlockAdr < sweepMemBlock.endBlockAdr) DO
  613. block := sweepBlockAdr + BlockHeaderSize;
  614. blockMark := block.mark; (* cache these values since they may be overwritten during concatenation *)
  615. blockGeneration := block.mark MOD GenerationMask;
  616. refCount := block.refCount;
  617. blockSize := block.size;
  618. IF (blockMark < generationMarkValues[blockGeneration])
  619. OR (refCount = -1) & EnableRefCount THEN
  620. IF (block.typeDesc # freeBlockTag) THEN
  621. Machine.Fill32(sweepBlockAdr + FreeBlockHeaderSize, blockSize - FreeBlockHeaderSize, DebugValue);
  622. END;
  623. freeBlock := block;
  624. IF lastFreeBlockAdr = NilVal THEN
  625. lastFreeBlockAdr := sweepBlockAdr;
  626. lastFreeBlock := freeBlock;
  627. lastFreeBlockSize := blockSize;
  628. ELSE
  629. IF StrongChecks THEN ASSERT(lastFreeBlockAdr + lastFreeBlockSize = sweepBlockAdr) END;
  630. (* there are at least two contiguous free blocks - merge them *)
  631. INC(lastFreeBlockSize, blockSize);
  632. Machine.Fill32(sweepBlockAdr, FreeBlockHeaderSize, DebugValue); (* rest was already cleared before *)
  633. END
  634. ELSIF StrongChecks THEN
  635. ASSERT(block.typeDesc = freeBlockTag);
  636. END;
  637. IF (lastFreeBlockAdr # NIL) & ((refCount # -1) & (blockMark >= (* sweepMarkValue *) generationMarkValues[blockGeneration]) OR (lastFreeBlockSize >= size) OR (sweepBlockAdr + blockSize = sweepMemBlock.endBlockAdr) )
  638. THEN (* no further merging is possible *)
  639. IF StrongChecks THEN ASSERT(sweepBlockAdr + blockSize <= sweepMemBlock.endBlockAdr) END;
  640. IF lastFreeBlockSize >= size THEN (* block found - may be too big *)
  641. p := lastFreeBlock;
  642. InitFreeBlock(lastFreeBlock, Unmarked, NilVal, size); (* convert this block into a free heap block and clear its data *)
  643. IF lastFreeBlockSize > size THEN (* block too big - divide block into two parts: block with required size and remaining free block *)
  644. IF StrongChecks THEN ASSERT(lastFreeBlockSize - size >= FreeBlockHeaderSize) END;
  645. freeBlock := p + size;
  646. InitFreeBlock(freeBlock, Unmarked, NilVal, lastFreeBlockSize - size);
  647. END;
  648. sweepBlockAdr := lastFreeBlockAdr + size; (* make sure next lazy sweep continues after block p *)
  649. time2 := Machine.GetTimer()-time1;
  650. INC(NgcSweepTime, time2);
  651. IF time2 > NgcSweepMax THEN NgcSweepMax := time2 END;
  652. RETURN;
  653. ELSE
  654. InitFreeBlock(lastFreeBlock, Unmarked, NilVal, lastFreeBlockSize); (* convert this block into a free heap block and clear its data *)
  655. IF EnableFreeLists THEN
  656. AppendFreeBlock(lastFreeBlock);
  657. END;
  658. END;
  659. lastFreeBlockAdr := NilVal;
  660. lastFreeBlock := NIL;
  661. END;
  662. sweepBlockAdr := sweepBlockAdr + blockSize
  663. END;
  664. sweepMemBlock := sweepMemBlock.next;
  665. IF sweepMemBlock # NIL THEN
  666. sweepBlockAdr := sweepMemBlock.beginBlockAdr
  667. ELSE
  668. sweepBlockAdr := NilVal
  669. END
  670. END;
  671. time2 := Machine.GetTimer()-time1;
  672. INC(NgcSweepTime, time2);
  673. IF time2 > NgcSweepMax THEN NgcSweepMax := time2 END;
  674. END LazySweep;
  675. (* -- useful for debugging --
  676. PROCEDURE CheckHeap;
  677. VAR memBlock {UNTRACED}: Machine.MemoryBlock; p, refBlock, currentArrayElemAdr, lastArrayElemAdr: ADDRESS;
  678. heapBlock {UNTRACED}: HeapBlock; staticTypeBlock {UNTRACED}: StaticTypeBlock; i: LONGINT;
  679. PROCEDURE CheckBlock(block: ADDRESS): BOOLEAN;
  680. VAR heapBlockAdr: ADDRESS;
  681. BEGIN
  682. IF block = NilVal THEN
  683. RETURN TRUE
  684. ELSE
  685. IF (block >= Machine.memBlockHead.beginBlockAdr) & (block < Machine.memBlockTail.endBlockAdr) THEN
  686. SYSTEM.GET(block + HeapBlockOffset, heapBlockAdr);
  687. IF (heapBlockAdr >= Machine.memBlockHead.beginBlockAdr) & (heapBlockAdr < Machine.memBlockTail.endBlockAdr) THEN
  688. RETURN TRUE
  689. ELSE
  690. RETURN FALSE
  691. END
  692. ELSE
  693. RETURN FALSE
  694. END
  695. END
  696. END CheckBlock;
  697. BEGIN
  698. memBlock := Machine.memBlockHead;
  699. WHILE memBlock # NIL DO
  700. p := memBlock.beginBlockAdr;
  701. WHILE p < memBlock.endBlockAdr DO
  702. heapBlock := SYSTEM.VAL(HeapBlock, p + BlockHeaderSize);
  703. IF heapBlock IS SystemBlock THEN
  704. ELSIF heapBlock IS RecordBlock THEN
  705. IF heapBlock.dataAdr # NilVal THEN
  706. SYSTEM.GET(heapBlock.dataAdr + TypeDescOffset, staticTypeBlock); ASSERT(staticTypeBlock # NIL);
  707. FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
  708. SYSTEM.GET(heapBlock.dataAdr + staticTypeBlock.pointerOffsets[i], refBlock);
  709. IF ~CheckBlock(refBlock) THEN
  710. Trace.String("SEVERE ERROR: RecordBlock = "); Trace.Hex(heapBlock.dataAdr, 8);
  711. Trace.String(" invalid reference at pointer offset = "); Trace.Hex(staticTypeBlock.pointerOffsets[i], 0); Trace.Ln
  712. END
  713. END;
  714. IF heapBlock IS ProtRecBlock THEN
  715. IF CheckBlock(heapBlock(ProtRecBlock).awaitingLock.head) &
  716. CheckBlock(heapBlock(ProtRecBlock).awaitingLock.tail) &
  717. CheckBlock(heapBlock(ProtRecBlock).awaitingCond.head) &
  718. CheckBlock(heapBlock(ProtRecBlock).awaitingCond.tail) &
  719. CheckBlock(heapBlock(ProtRecBlock).lockedBy) THEN
  720. ELSE
  721. Trace.String("SEVERE ERROR in awaiting queues of block = "); Trace.Hex(heapBlock.dataAdr, 8); Trace.Ln
  722. END
  723. END
  724. ELSE
  725. Trace.StringLn("SEVERE ERROR: heapBlock.dataAdr = NilVal for RecordBlock or ProtRecBlock")
  726. END;
  727. ELSIF heapBlock IS ArrayBlock THEN
  728. IF heapBlock.dataAdr # NilVal THEN
  729. SYSTEM.GET(heapBlock.dataAdr + TypeDescOffset, staticTypeBlock); ASSERT(staticTypeBlock # NIL);
  730. SYSTEM.GET(heapBlock.dataAdr + 2 * AddressSize, currentArrayElemAdr);
  731. SYSTEM.GET(heapBlock.dataAdr, lastArrayElemAdr);
  732. WHILE currentArrayElemAdr <= lastArrayElemAdr DO
  733. FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
  734. SYSTEM.GET(currentArrayElemAdr + staticTypeBlock.pointerOffsets[i], refBlock);
  735. IF ~CheckBlock(refBlock) THEN
  736. Trace.String("SEVERE ERROR in ArrayBlock = "); Trace.Hex(currentArrayElemAdr, 8);
  737. Trace.String(" invalid reference at pointer offset = "); Trace.Hex(staticTypeBlock.pointerOffsets[i], 0); Trace.Ln
  738. END
  739. END;
  740. INC(currentArrayElemAdr, staticTypeBlock.recSize)
  741. END
  742. ELSE
  743. Trace.StringLn("SEVERE ERROR: heapBlock.dataAdr = NilVal for ArrayBlock")
  744. END
  745. ELSIF heapBlock IS FreeBlock THEN
  746. ELSE
  747. Trace.StringLn("Invalid heap block type")
  748. END;
  749. p := p + heapBlock.size;
  750. END;
  751. memBlock := memBlock.next
  752. END
  753. END CheckHeap;
  754. *)
  755. (* CheckCandidates - Check which candidates could be pointers, and mark them. (exported for debugging only) *)
  756. PROCEDURE CheckCandidates*;
  757. CONST MinDataOffset = BlockHeaderSize + SIZEOF(HeapBlockDesc) + BlockHeaderSize; (* minimal offset of data address with respect to block start address *)
  758. VAR i, j, h: LONGINT; p, blockStart: ADDRESS; memBlock {UNTRACED}: Machine.MemoryBlock;
  759. heapBlock {UNTRACED}: HeapBlock;
  760. BEGIN
  761. (* {numCandidates > 0} *)
  762. (* first sort them in increasing order using shellsort *)
  763. h := 1; REPEAT h := h*3 + 1 UNTIL h > numCandidates;
  764. REPEAT
  765. h := h DIV 3; i := h;
  766. WHILE i < numCandidates DO
  767. p := candidates[i]; j := i;
  768. WHILE (j >= h) & (candidates[j-h] > p) DO
  769. candidates[j] := candidates[j-h]; j := j-h;
  770. END;
  771. candidates[j] := p; INC(i)
  772. END
  773. UNTIL h = 1;
  774. (* sweep phase *)
  775. i := 0;
  776. p := candidates[i];
  777. memBlock := Machine.memBlockHead;
  778. WHILE memBlock # NIL DO
  779. blockStart := memBlock.beginBlockAdr;
  780. WHILE (i < numCandidates) & (blockStart < memBlock.endBlockAdr) DO
  781. IF p < blockStart + MinDataOffset THEN (* candidate missed *)
  782. INC(i);
  783. IF i < numCandidates THEN
  784. p := candidates[i]
  785. END
  786. ELSE
  787. heapBlock := SYSTEM.VAL(HeapBlock, blockStart + BlockHeaderSize);
  788. IF (p = heapBlock.dataAdr) & ~(heapBlock IS FreeBlock) THEN (* heap block must not be a free block but any other heap block type *)
  789. Mark(SYSTEM.VAL(ANY, p))
  790. END;
  791. blockStart := blockStart + heapBlock.size;
  792. END
  793. END;
  794. memBlock := memBlock.next
  795. END;
  796. numCandidates := 0
  797. END CheckCandidates;
  798. (* Check validity of single pointer candidate and enter it into the list of candidates *)
  799. PROCEDURE Candidate*(p: ADDRESS);
  800. VAR memBlock, memBlockX {UNTRACED}: Machine.MemoryBlock;
  801. tdAdr, heapBlockAdr: ADDRESS;
  802. tdPtr{UNTRACED}: POINTER {UNSAFE} TO RECORD typeAdr: ADDRESS END;
  803. hbPtr{UNTRACED}: POINTER {UNSAFE} TO RECORD heapBlock: HeapBlock END;
  804. heapBlock {UNTRACED}: HeapBlock;
  805. BEGIN
  806. IF p MOD SIZEOF(ADDRESS) # 0 THEN RETURN END;
  807. IF (p >= Machine.memBlockHead.beginBlockAdr) & (p < Machine.memBlockTail.endBlockAdr) THEN
  808. memBlock := Machine.memBlockHead;
  809. WHILE memBlock # NIL DO
  810. IF (p + HeapBlockOffset >= memBlock.beginBlockAdr) & (p + HeapBlockOffset < memBlock.endBlockAdr) THEN
  811. hbPtr := p + HeapBlockOffset;
  812. heapBlock := hbPtr.heapBlock;
  813. heapBlockAdr := heapBlock ;
  814. IF heapBlockAdr MOD SIZEOF(ADDRESS) # 0 THEN RETURN END;
  815. tdAdr :=heapBlockAdr + TypeDescOffset;
  816. (* check if tdAdr is a valid pointer in the heap *)
  817. memBlockX := Machine.memBlockHead;
  818. WHILE memBlockX # NIL DO
  819. IF (tdAdr >= memBlockX.beginBlockAdr) & (tdAdr < memBlockX.endBlockAdr) THEN
  820. (* IF (heapBlock.mark >= currentMarkValue) THEN RETURN END;*)
  821. tdPtr := tdAdr;
  822. tdAdr := tdPtr.typeAdr;
  823. (* check whether tdAdr is a valid type descriptor address *)
  824. IF (tdAdr = systemBlockTag) OR (tdAdr = recordBlockTag) OR (tdAdr = protRecBlockTag) OR (tdAdr = arrayBlockTag) THEN
  825. candidates[numCandidates] := p;
  826. INC(numCandidates);
  827. IF numCandidates = LEN(candidates) THEN CheckCandidates END
  828. END;
  829. RETURN; (* found *)
  830. END;
  831. memBlockX := memBlockX.next
  832. END;
  833. RETURN; (* not found *)
  834. END;
  835. memBlock := memBlock.next
  836. END
  837. END
  838. END Candidate;
  839. (** RegisterCandidates - Register a block of pointer candidates *)
  840. PROCEDURE RegisterCandidates*(adr: ADDRESS; size: SIZE);
  841. VAR end, p: ADDRESS;
  842. BEGIN
  843. ASSERT (adr MOD AddressSize = 0);
  844. ASSERT (size MOD AddressSize = 0);
  845. (* current processor must hold Heaps lock *)
  846. end := adr + size;
  847. WHILE adr # end DO
  848. SYSTEM.GET(adr, p);
  849. Candidate(p);
  850. INC(adr, AddressSize)
  851. END
  852. END RegisterCandidates;
  853. (* Check reachability of finalized objects. *)
  854. PROCEDURE CheckFinalizedObjects;
  855. VAR n, p, t: FinalizerNode; heapBlock {UNTRACED}: HeapBlock;
  856. PROCEDURE MarkDelegate(p: Finalizer);
  857. VAR pointer {UNTRACED}: ANY;
  858. BEGIN
  859. SYSTEM.GET(ADDRESSOF(p)+SIZEOF(ADDRESS),pointer);
  860. IF pointer # NIL THEN Mark(pointer) END;
  861. END MarkDelegate;
  862. BEGIN
  863. n := checkRoot;
  864. WHILE n # NIL DO (* move unmarked checked objects to finalize list *)
  865. SYSTEM.GET(SYSTEM.VAL(ADDRESS, n.objWeak) + HeapBlockOffset, heapBlock);
  866. IF (heapBlock.mark < generationMarkValues[heapBlock.mark MOD GenerationMask])
  867. OR (heapBlock.refCount = -1) & EnableRefCount
  868. THEN
  869. IF n = checkRoot THEN checkRoot := n.nextFin ELSE p.nextFin := n.nextFin END;
  870. n.objStrong := n.objWeak; (* anchor the object for finalization *)
  871. n.finalizerStrong := n.finalizer; (* anchor the finalizer for finalization *)
  872. t := n.nextFin; n.nextFin := finalizeRoot; finalizeRoot := n; n := t;
  873. IF Stats THEN DEC(NfinalizeAlive); INC(NfinalizeDead) END
  874. ELSE
  875. p := n; n := n.nextFin
  876. END
  877. END;
  878. (* now trace the weak references to keep finalized objects alive during this collection *)
  879. n := finalizeRoot;
  880. WHILE n # NIL DO
  881. MarkDelegate(n.finalizerStrong);
  882. Mark(n.objStrong); n := n.nextFin
  883. END;
  884. n := checkRoot;
  885. WHILE n # NIL DO (* list of objects that had been marked before entering CheckFinalizedObjects *)
  886. (* we still have to mark the weak finalizers, as they might have not been marked before *)
  887. MarkDelegate(n.finalizer); n := n.nextFin
  888. END;
  889. END CheckFinalizedObjects;
  890. (** Return the next scheduled finalizer or NIL if none available. Called by finalizer object in Kernel. *)
  891. PROCEDURE GetFinalizer* (): FinalizerNode;
  892. VAR n: FinalizerNode;
  893. BEGIN
  894. n := NIL;
  895. IF finalizeRoot # NIL THEN
  896. Machine.Acquire(Machine.Heaps);
  897. n := finalizeRoot; (* take one finalizer *)
  898. IF n # NIL THEN
  899. finalizeRoot := n.nextFin; n.nextFin := NIL;
  900. IF Stats THEN DEC(NfinalizeDead) END;
  901. END;
  902. Machine.Release(Machine.Heaps);
  903. END;
  904. RETURN n
  905. END GetFinalizer;
  906. (** 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. *)
  907. PROCEDURE CleanupModuleFinalizers*(codeAdr: ADDRESS; codeLen: SIZE; CONST name: ARRAY OF CHAR);
  908. VAR n, p, t: FinalizerNode; codeEnd: ADDRESS; N1, N2: LONGINT;
  909. BEGIN
  910. codeEnd := codeAdr + codeLen; N1 := 0; N2 := 0;
  911. Machine.Acquire(Machine.Heaps);
  912. n := checkRoot;
  913. WHILE n # NIL DO (* iterate over checked list *)
  914. t := n; n := n.nextFin;
  915. IF (codeAdr <= SYSTEM.VAL (ADDRESS, t.finalizer)) & (SYSTEM.VAL (ADDRESS, t.finalizer) <= codeEnd) THEN
  916. IF t = checkRoot THEN checkRoot := t.nextFin ELSE p.nextFin := t.nextFin END; (* remove from list *)
  917. IF Stats THEN DEC(NfinalizeAlive) END;
  918. INC(N1)
  919. ELSE
  920. p := t
  921. END
  922. END;
  923. (* also remove finalizers from list, so they won't be called *)
  924. n := finalizeRoot;
  925. WHILE n # NIL DO (* iterate over finalized list *)
  926. t := n; n := n.nextFin;
  927. IF (codeAdr <= SYSTEM.VAL (ADDRESS, t.finalizer)) & (SYSTEM.VAL (ADDRESS, t.finalizer) <= codeEnd) THEN
  928. IF t = finalizeRoot THEN finalizeRoot := t.nextFin ELSE p.nextFin := t.nextFin END; (* remove from list *)
  929. IF Stats THEN DEC(NfinalizeDead) END;
  930. INC(N2)
  931. ELSE
  932. p := t
  933. END
  934. END;
  935. Machine.Release(Machine.Heaps);
  936. IF (N1 # 0) OR (N2 # 0) THEN
  937. Machine.Acquire (Machine.TraceOutput);
  938. Trace.String(name); Trace.Char(" ");
  939. Trace.Int(N1, 1); Trace.String(" discarded finalizers, ");
  940. Trace.Int(N2, 1); Trace.StringLn (" pending finalizers");
  941. Machine.Release (Machine.TraceOutput);
  942. END
  943. END CleanupModuleFinalizers;
  944. (* 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. *)
  945. PROCEDURE AddRootObject*(rootObject: RootObject);
  946. BEGIN
  947. IF rootObject = NIL THEN (* nothing *)
  948. ELSIF CheckPointer(rootObject) THEN
  949. (* object in heap, must be fully marked and traversed *)
  950. Mark(rootObject)
  951. ELSE
  952. (* object in bootfile, traverse as root object only *)
  953. rootObject.nextRoot := rootList; rootList := rootObject; (* link root list *)
  954. END;
  955. END AddRootObject;
  956. (* interruptible garbage collector for native A2 *)
  957. PROCEDURE CollectGarbage*(root : RootObject);
  958. VAR
  959. obj: RootObject;
  960. time1, time2: HUGEINT;
  961. f: FreeBlock;
  962. i: LONGINT;
  963. BEGIN
  964. (* 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 *)
  965. (*!
  966. Do not use windows functionality such as trace here in general -- can lead to deadlock when stopped processes are in writing to a file
  967. *)
  968. (* GC may run only if and only if sweep phase has been completed *)
  969. IF ~EnableFreeLists OR (sweepMemBlock = NIL) & (sweepMarkValue = currentMarkValue) THEN
  970. IF Stats THEN
  971. Nmark := 0; Nmarked := 0;
  972. INC(Ngc);
  973. time1 := Machine.GetTimer ();
  974. END;
  975. numCandidates := 0;
  976. rootList := NIL;
  977. INC(currentMarkValue, GenerationMask);
  978. FOR i := 0 TO currentGeneration DO
  979. generationMarkValues[i] := currentMarkValue;
  980. END;
  981. (* TRACE(currentGeneration); *)
  982. IF currentGeneration = Young THEN
  983. (* sweep and enter all old blocks containing old -> new pointers *)
  984. SweepCardSet();
  985. ClearCardSet();
  986. END;
  987. AddRootObject(root);
  988. IF GCType = HeuristicStackInspectionGC THEN
  989. REPEAT
  990. REPEAT
  991. IF rootList # NIL THEN (* check root objects *)
  992. REPEAT
  993. obj := rootList; (* get head object *)
  994. rootList := rootList.nextRoot; (* link to next *)
  995. obj.FindRoots; (* Mark called via AddRootObject, but not for objects in static heap *)
  996. UNTIL rootList = NIL
  997. END;
  998. IF numCandidates # 0 THEN CheckCandidates END
  999. UNTIL (numCandidates = 0) & (rootList = NIL);
  1000. MarkRealtimeObjects;
  1001. CheckFinalizedObjects;
  1002. UNTIL rootList = NIL;
  1003. ELSIF GCType = MetaDataForStackGC THEN
  1004. REPEAT
  1005. IF rootList # NIL THEN (* check root objects *)
  1006. REPEAT
  1007. obj := rootList; (* get head object *)
  1008. rootList := rootList.nextRoot; (* link to next *)
  1009. obj.FindRoots; (* Mark called via AddRootObject, but not for objects in static heap *)
  1010. UNTIL rootList = NIL
  1011. END;
  1012. MarkRealtimeObjects;
  1013. CheckFinalizedObjects
  1014. UNTIL rootList = NIL;
  1015. ELSE
  1016. HALT(901) (* wrong GCType constant *)
  1017. END;
  1018. IF Stats THEN
  1019. time2 := Machine.GetTimer ();
  1020. NgcCyclesLastRun := time2 - time1;
  1021. IF NgcCyclesLastRun > NgcCyclesMax THEN NgcCyclesMax := NgcCyclesLastRun; END;
  1022. INC(NgcCyclesAllRuns, NgcCyclesLastRun);
  1023. NgcCyclesMark := NgcCyclesLastRun
  1024. END;
  1025. (* TRACE(LONGINT((time2-time1) DIV (1024*1024))); *)
  1026. END;
  1027. IF EnableFreeLists THEN GetFreeBlock(MAX(SIZE), f) END;
  1028. END CollectGarbage;
  1029. PROCEDURE InvokeGC*;
  1030. BEGIN
  1031. ASSERT(gcStatus # NIL);
  1032. gcStatus.SetgcOngoing(TRUE);
  1033. END InvokeGC;
  1034. PROCEDURE ReturnBlocks;
  1035. VAR memBlock {UNTRACED}, free{UNTRACED}: Machine.MemoryBlock; p: ADDRESS; heapBlock {UNTRACED}: HeapBlock; f: FreeBlock;
  1036. BEGIN
  1037. GetFreeBlock(MAX(SIZE), f);
  1038. memBlock := Machine.memBlockHead;
  1039. WHILE memBlock # NIL DO
  1040. free := NIL;
  1041. p := memBlock.beginBlockAdr;
  1042. heapBlock := SYSTEM.VAL(HeapBlock, p + BlockHeaderSize);
  1043. IF (heapBlock IS FreeBlock) & (p + heapBlock.size = memBlock.endBlockAdr) THEN
  1044. free := memBlock;
  1045. END;
  1046. memBlock := memBlock.next;
  1047. IF free # NIL THEN
  1048. Machine.FreeMemBlock(free)
  1049. END;
  1050. END;
  1051. sweepMemBlock := NIL; (* restart LazySweep *)
  1052. ClearFreeLists;
  1053. END ReturnBlocks;
  1054. (*
  1055. caller must hold the Heaps lock
  1056. required for low level tracing
  1057. *)
  1058. PROCEDURE FullSweep*;
  1059. VAR p {UNTRACED}: FreeBlock;
  1060. BEGIN
  1061. GetFreeBlock(MAX(SIZE), p);
  1062. END FullSweep;
  1063. PROCEDURE LazySweepGC*;
  1064. VAR p {UNTRACED}: FreeBlock;
  1065. BEGIN
  1066. (* invoke mark phase, mark phase starts at next scheduler interrupt *)
  1067. GC;
  1068. (* return blocks now *)
  1069. Machine.Acquire(Machine.Heaps);
  1070. (* trying to satisfy a request of MAX(SIZE) bytes will never succeed - lazy sweep runs until end of heap *)
  1071. GetFreeBlock(MAX(SIZE), p);
  1072. IF EnableReturnBlocks THEN ReturnBlocks END;
  1073. Machine.Release(Machine.Heaps);
  1074. END LazySweepGC;
  1075. VAR youngCounts: LONGINT;
  1076. (* initialize a free heap block *)
  1077. PROCEDURE InitFreeBlock(freeBlock: FreeBlockU; mark: LONGINT; dataAdr: ADDRESS; size: SIZE);
  1078. CONST FreeBlockHeaderSize = SIZEOF(FreeBlockDesc) + BlockHeaderSize;
  1079. BEGIN
  1080. (* initialize heap block header *)
  1081. freeBlock.typeDesc := freeBlockTag;
  1082. freeBlock.heapBlock := NIL;
  1083. (* initialize heap block fields *)
  1084. freeBlock.mark := mark + Young;
  1085. freeBlock.refCount := 1;
  1086. freeBlock.dataAdr := dataAdr;
  1087. freeBlock.size := size;
  1088. (* initialize free block fields *)
  1089. freeBlock.next := NIL;
  1090. END InitFreeBlock;
  1091. VAR throughput := 0 : SIZE;
  1092. (* NewBlock - Allocate a heap block. {(size MOD BlockSize = 0)}. Caller must hold Heap lock. *)
  1093. PROCEDURE NewBlock(size: SIZE): ADDRESS;
  1094. VAR try: LONGINT; p: FreeBlock; freeBlock : FreeBlockU; memBlock {UNTRACED}: Machine.MemoryBlock;
  1095. beginHeapBlockAdr, endHeapBlockAdr: ADDRESS;
  1096. PROCEDURE CheckPostGC;
  1097. BEGIN
  1098. IF (sweepMarkValue < currentMarkValue) & EnableReturnBlocks THEN (* GC has run but no Sweep yet -- time to do post-gc cleanup *)
  1099. ReturnBlocks
  1100. END;
  1101. END CheckPostGC;
  1102. BEGIN
  1103. CheckPostGC;
  1104. try := 1;
  1105. p := NIL;
  1106. IF (GC = NilGC) OR (throughput < 32*1024*1024) OR TRUE THEN
  1107. GetFreeBlock(size, p);
  1108. IF (p=NIL) THEN (* try restart sweep for once *)
  1109. GetFreeBlock(size, p);
  1110. END;
  1111. ELSE
  1112. throughput := 0;
  1113. END;
  1114. WHILE (p = NIL) & (try <= MaxTries) DO
  1115. IF currentGeneration = Young THEN INC(youngCounts) END;
  1116. IF youngCounts > 100 THEN
  1117. currentGeneration := Old;
  1118. END;
  1119. Machine.Release(Machine.Heaps); (* give up control *)
  1120. GC; (* try to free memory (other processes may also steal memory now) *)
  1121. Machine.Acquire(Machine.Heaps);
  1122. CheckPostGC;
  1123. sweepMemBlock := NIL;
  1124. GetFreeBlock(size, p);
  1125. IF (currentGeneration = Young) & (p=NIL) THEN
  1126. currentGeneration := Old;
  1127. Machine.Release(Machine.Heaps); (* give up control *)
  1128. GC; (* try to free memory (other processes may also steal memory now) *)
  1129. Machine.Acquire(Machine.Heaps);
  1130. CheckPostGC;
  1131. currentGeneration := Young;
  1132. sweepMemBlock := NIL;
  1133. GetFreeBlock(size, p);
  1134. END;
  1135. IF youngCounts > 100 THEN
  1136. currentGeneration := Young;
  1137. youngCounts := 0;
  1138. END;
  1139. IF p = NIL THEN
  1140. Machine.ExpandHeap(try, size, memBlock, beginHeapBlockAdr, endHeapBlockAdr); (* try to extend the heap *)
  1141. IF endHeapBlockAdr > beginHeapBlockAdr THEN
  1142. freeBlock := beginHeapBlockAdr + BlockHeaderSize;
  1143. InitFreeBlock(freeBlock, Unmarked, NilVal, endHeapBlockAdr - beginHeapBlockAdr);
  1144. Machine.SetMemoryBlockEndAddress(memBlock, endHeapBlockAdr); (* end address of expanded block must set after free block is fit in memory block *)
  1145. IF EnableFreeLists THEN AppendFreeBlock(freeBlock)
  1146. ELSE
  1147. sweepMemBlock := memBlock;
  1148. sweepBlockAdr := beginHeapBlockAdr;
  1149. END;
  1150. GetFreeBlock(size, p);
  1151. sweepMemBlock := NIL; (* restart sweep from beginning after having taken big block in order to avoid fragmentation *)
  1152. END;
  1153. INC(try)
  1154. END;
  1155. END;
  1156. IF p # NIL THEN
  1157. IF Stats THEN INC(Nnew); INC(NnewBytes, size) END;
  1158. ASSERT(p.size >= size);
  1159. RETURN p;
  1160. ELSE (* try = MaxTries *)
  1161. SYSTEM.HALT(14) (* out of memory *)
  1162. END;
  1163. END NewBlock;
  1164. PROCEDURE CheckBP(bp: ADDRESS): ADDRESS;
  1165. VAR n: ADDRESS;
  1166. BEGIN
  1167. SYSTEM.GET(bp,n);
  1168. IF ODD(n) THEN bp := bp + SIZEOF(ADDRESS) END;
  1169. RETURN bp;
  1170. END CheckBP;
  1171. PROCEDURE SetPC*(p: DataBlockU);
  1172. VAR bp: ADDRESS;
  1173. BEGIN
  1174. IF p # NIL THEN
  1175. bp := CheckBP(SYSTEM.GetFramePointer());
  1176. SYSTEM.GET(bp, bp);
  1177. bp := CheckBP(bp);
  1178. SYSTEM.GET(bp+SIZEOF(ADDRESS), p.heapBlock.heapBlock);
  1179. END;
  1180. END SetPC;
  1181. (** NewSys - Implementation of SYSTEM.NEW. *)
  1182. PROCEDURE NewSys*(VAR p: ANY; size: SIZE; isRealtime: BOOLEAN);
  1183. VAR
  1184. blockSize, systemBlockSize: SIZE; systemBlockAdr, dataBlockAdr: ADDRESS;
  1185. systemBlock: HeapBlockU;
  1186. dataBlock: DataBlockU;
  1187. BEGIN
  1188. systemBlockSize := BlockHeaderSize + SIZEOF(SystemBlockDesc);
  1189. INC(systemBlockSize, (-systemBlockSize) MOD ArrayAlignment); (* round up to multiple of ArrayAlignment to ensure alignment of first data element to 0 MOD ArrayAlignment *)
  1190. blockSize := systemBlockSize + BlockHeaderSize + size;
  1191. INC(blockSize, (-blockSize) MOD BlockSize); (* round up to multiple of BlockSize *)
  1192. Machine.Acquire(Machine.Heaps);
  1193. systemBlockAdr:= NewBlock(blockSize);
  1194. IF systemBlockAdr # 0 THEN
  1195. systemBlock := systemBlockAdr;
  1196. dataBlockAdr := systemBlockAdr + systemBlockSize;
  1197. dataBlock := dataBlockAdr;
  1198. systemBlock.typeDesc := systemBlockTag;
  1199. dataBlock.typeDesc := NilVal;
  1200. dataBlock.heapBlock := systemBlock;
  1201. systemBlock.mark := currentMarkValue + Young;
  1202. systemBlock.refCount := 0;
  1203. systemBlock.dataAdr := dataBlockAdr;
  1204. systemBlock.size := blockSize;
  1205. (*! disable realtime block handling for the time being
  1206. IF isRealtime THEN
  1207. systemBlock.nextRealtime := realtimeList;
  1208. realtimeList := systemBlock
  1209. ELSE
  1210. systemBlock.nextRealtime := NIL
  1211. END;
  1212. *)
  1213. SetPC(dataBlock);
  1214. (*CheckAssignment(ADDRESS OF p, dataBlock);*)
  1215. p := dataBlock;
  1216. (* clear could be done outside lock because SysBlks are not traced, but for conformity it is done inside the lock *)
  1217. Machine.Fill32(dataBlockAdr, blockSize - systemBlockSize - BlockHeaderSize, 0); (* clear everything from dataBlockAdr until end of block *)
  1218. ELSE
  1219. p := NIL
  1220. END;
  1221. IF allocationLogger # NIL THEN allocationLogger(p) END;
  1222. Machine.Release(Machine.Heaps)
  1223. END NewSys;
  1224. (** NewRec - Implementation of NEW with a record. *)
  1225. PROCEDURE NewRec*(VAR p: ANY; tag: ADDRESS; isRealtime: BOOLEAN);
  1226. VAR
  1227. size, blockSize: SIZE; recordBlockAdr, dataBlockAdr : ADDRESS;
  1228. recordBlock: RecordBlockU;
  1229. dataBlock: DataBlockU;
  1230. typeDesc: StaticTypeBlockU;
  1231. BEGIN
  1232. typeDesc := tag;
  1233. IF ProtTypeBit IN typeDesc.info.flags THEN
  1234. NewProtRec(p, tag, isRealtime);
  1235. SetPC(p);
  1236. ELSE
  1237. size := typeDesc.recSize;
  1238. (* the block size is the sum of the size of the RecordBlock and the DataBlock.
  1239. Two extra fields per subblock contain the tag and the reference to the heap block *)
  1240. blockSize := BlockHeaderSize + SIZEOF(RecordBlockDesc) + BlockHeaderSize + size;
  1241. INC(blockSize, (-blockSize) MOD BlockSize); (* round up to multiple of BlockSize *)
  1242. Machine.Acquire(Machine.Heaps);
  1243. recordBlockAdr := NewBlock(blockSize);
  1244. IF recordBlockAdr # 0 THEN
  1245. recordBlock := recordBlockAdr;
  1246. dataBlockAdr := recordBlockAdr + SIZEOF(RecordBlockDesc) + BlockHeaderSize;
  1247. dataBlock := dataBlockAdr;
  1248. recordBlock.typeDesc := recordBlockTag;
  1249. dataBlock.typeDesc := tag;
  1250. dataBlock.heapBlock := recordBlockAdr;
  1251. recordBlock.mark := currentMarkValue + Young;
  1252. recordBlock.refCount := 0;
  1253. recordBlock.dataAdr := dataBlockAdr;
  1254. recordBlock.size := blockSize;
  1255. (*! disable realtime block handling for the time being
  1256. IF isRealtime THEN
  1257. recordBlock.nextRealtime := realtimeList;
  1258. realtimeList := recordBlock
  1259. ELSE
  1260. recordBlock.nextRealtime := NIL
  1261. END;
  1262. *)
  1263. SetPC(dataBlock);
  1264. p := dataBlock;
  1265. IF (currentGeneration = Young) OR (youngCounts > 0) THEN
  1266. EnterInCardSet(ADDRESS OF p);
  1267. END;
  1268. (* clear must be done inside lock to ensure all traced pointer fields are initialized to NIL *)
  1269. Machine.Fill32(dataBlockAdr, blockSize - SIZEOF(RecordBlockDesc) - 2 * BlockHeaderSize, 0); (* clear everything from dataBlockAdr until end of block *)
  1270. ELSE
  1271. p := NIL
  1272. END;
  1273. IF allocationLogger # NIL THEN allocationLogger(p) END;
  1274. Machine.Release(Machine.Heaps)
  1275. END;
  1276. END NewRec;
  1277. (** NewProtRec - Implementation of NEW with a protected record. *)
  1278. PROCEDURE NewProtRec*(VAR p: ANY; tag: ADDRESS; isRealtime: BOOLEAN);
  1279. VAR size, blockSize: SIZE; protRecBlockAdr, dataBlockAdr: ADDRESS;
  1280. protRecBlock: ProtRecBlockU;
  1281. dataBlock: DataBlockU;
  1282. i: LONGINT;
  1283. typeDesc: StaticTypeBlockU;
  1284. BEGIN
  1285. typeDesc := tag;
  1286. size := typeDesc.recSize;
  1287. blockSize := BlockHeaderSize + SIZEOF(ProtRecBlockDesc) + BlockHeaderSize + size;
  1288. INC(blockSize, (-blockSize) MOD BlockSize); (* round up to multiple of BlockSize *)
  1289. Machine.Acquire(Machine.Heaps);
  1290. protRecBlockAdr := NewBlock(blockSize);
  1291. IF protRecBlockAdr # 0 THEN
  1292. (* fill muste be done first in order to remove DEAD from pointers (referecne counting!) *)
  1293. Machine.Fill32(protRecBlockAdr, blockSize-BlockHeaderSize, 0); (* clear everything from dataBlockAdr to end of block *)
  1294. protRecBlock := protRecBlockAdr;
  1295. dataBlockAdr := protRecBlockAdr + SIZEOF(ProtRecBlockDesc) + BlockHeaderSize;
  1296. dataBlock := dataBlockAdr;
  1297. protRecBlock.typeDesc := protRecBlockTag;
  1298. dataBlock.typeDesc := tag;
  1299. dataBlock.heapBlock := protRecBlockAdr;
  1300. protRecBlock.mark := currentMarkValue + Young;
  1301. protRecBlock.refCount := 0;
  1302. protRecBlock.dataAdr := dataBlockAdr;
  1303. protRecBlock.size := blockSize;
  1304. (*! disable realtime block handling for the time being
  1305. IF isRealtime THEN
  1306. protRecBlock.nextRealtime := realtimeList;
  1307. realtimeList := protRecBlock
  1308. ELSE
  1309. protRecBlock.nextRealtime := NIL
  1310. END;
  1311. *)
  1312. protRecBlock.count := 0;
  1313. protRecBlock.awaitingLock.head := NIL;
  1314. protRecBlock.awaitingLock.tail := NIL;
  1315. protRecBlock.awaitingCond.head := NIL;
  1316. protRecBlock.awaitingCond.tail := NIL;
  1317. protRecBlock.lockedBy := NIL;
  1318. protRecBlock.locked := FALSE;
  1319. protRecBlock.lock := NIL;
  1320. FOR i := 0 TO NumPriorities - 1 DO
  1321. protRecBlock.waitingPriorities[i] := 0
  1322. END;
  1323. INC(protRecBlock.waitingPriorities[0]); (* set sentinel value: assume that idle process with priority 0 waits on this resource *)
  1324. SetPC(dataBlock);
  1325. p := dataBlock;
  1326. IF (currentGeneration = Young) OR (youngCounts > 0) THEN
  1327. EnterInCardSet(ADDRESS OF p);
  1328. END;
  1329. (* clear must be done inside lock to ensure all traced pointer fields are initialized to NIL *)
  1330. ELSE
  1331. p := NIL
  1332. END;
  1333. IF allocationLogger # NIL THEN allocationLogger(p) END;
  1334. Machine.Release(Machine.Heaps)
  1335. END NewProtRec;
  1336. (** NewArr - Implementation of NEW with an array containing pointers. *)
  1337. PROCEDURE NewArr*(VAR p: ANY; elemTag: ADDRESS; numElems, numDims: SIZE; isRealtime: BOOLEAN);
  1338. VAR arrayBlockAdr, dataBlockAdr: ADDRESS;
  1339. elemSize, arrSize, blockSize, arrayBlockSize, fillSize, size, arrayDataOffset: SIZE;
  1340. firstElem: ADDRESS;
  1341. ptrOfs: ADDRESS;
  1342. elemType: StaticTypeBlockU;
  1343. arrayBlock: ArrayBlockU;
  1344. dataBlock: ArrayDataBlockU;
  1345. BEGIN
  1346. elemType := elemTag;
  1347. elemSize := elemType.recSize;
  1348. arrSize := numElems * elemSize;
  1349. IF arrSize = 0 THEN
  1350. NewSys(p, numDims * AddressSize + 3 * AddressSize, isRealtime); (* no data, thus no specific alignment *)
  1351. SetPC(p);
  1352. ELSE
  1353. ASSERT(BlockHeaderSize MOD ArrayAlignment = 0);
  1354. arrayDataOffset := numDims * AddressSize + 3 * AddressSize;
  1355. INC(arrayDataOffset, (-arrayDataOffset) MOD ArrayAlignment); (* round up to multiple of ArrayAlignment to ensure that first array element is aligned at 0 MOD ArrayAlignment *)
  1356. ptrOfs := elemType.pointerOffsets;
  1357. IF ptrOfs = MinPtrOfs - AddressSize THEN (* no pointers in element type *)
  1358. size := arrayDataOffset + arrSize;
  1359. NewSys(p, size, isRealtime);
  1360. SetPC(p);
  1361. ELSE
  1362. arrayBlockSize := BlockHeaderSize + SIZEOF(ArrayBlockDesc);
  1363. INC(arrayBlockSize, (-arrayBlockSize) MOD ArrayAlignment); (* do. *)
  1364. blockSize := arrayBlockSize + BlockHeaderSize + (arrayDataOffset + arrSize);
  1365. INC(blockSize, (-blockSize) MOD BlockSize); (* round up to multiple of BlockSize *)
  1366. Machine.Acquire(Machine.Heaps);
  1367. arrayBlockAdr := NewBlock(blockSize);
  1368. IF arrayBlockAdr # 0 THEN
  1369. arrayBlock := arrayBlockAdr;
  1370. dataBlockAdr := arrayBlockAdr + arrayBlockSize (* - BlockHeaderSize + BlockHeaderSize *);
  1371. dataBlock := dataBlockAdr;
  1372. arrayBlock.typeDesc := arrayBlockTag;
  1373. dataBlock.typeDesc := elemType;
  1374. dataBlock.heapBlock := arrayBlock;
  1375. arrayBlock.mark := currentMarkValue + Young;
  1376. arrayBlock.refCount := 0;
  1377. arrayBlock.dataAdr := dataBlockAdr;
  1378. arrayBlock.size := blockSize;
  1379. (*! disable realtime block handling for the time being
  1380. IF isRealtime THEN
  1381. arrayBlock.nextRealtime := realtimeList;
  1382. realtimeList := arrayBlock
  1383. ELSE
  1384. arrayBlock.nextRealtime := NIL
  1385. END;
  1386. *)
  1387. (* 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. , *)
  1388. fillSize := blockSize - arrayBlockSize - BlockHeaderSize;
  1389. Machine.Fill32(dataBlockAdr, fillSize, 0); (* clear everything from dataBlockAdr until end of block *)
  1390. firstElem := dataBlockAdr + arrayDataOffset;
  1391. dataBlock.numElems := numElems;
  1392. dataBlock.current := NIL;
  1393. dataBlock.first := firstElem;
  1394. SetPC(dataBlock);
  1395. p := dataBlock;
  1396. IF (currentGeneration = Young) OR (youngCounts > 0) THEN
  1397. EnterInCardSet(ADDRESS OF p);
  1398. END;
  1399. ELSE
  1400. p := NIL
  1401. END;
  1402. IF allocationLogger # NIL THEN allocationLogger(p) END;
  1403. Machine.Release(Machine.Heaps)
  1404. END
  1405. END
  1406. END NewArr;
  1407. TYPE
  1408. UnsafeArray= POINTER {UNSAFE,UNTRACED} TO UnsafeArrayDesc;
  1409. UnsafeArrayDesc = RECORD (ArrayDataBlockDesc)
  1410. len: ARRAY 8 OF SIZE;
  1411. END;
  1412. (* replacement for overcomplicated code emission -- at the cost of a slightly increased runtime cost *)
  1413. PROCEDURE NewArray*(CONST a: ARRAY OF SIZE; tag: ADDRESS; staticElements, elementSize: SIZE; VAR dest: ANY);
  1414. VAR p: ANY; dim: SIZE;
  1415. PROCEDURE GetSize(): SIZE;
  1416. VAR i: SIZE; size: SIZE;
  1417. BEGIN
  1418. size := 1;
  1419. FOR i := 0 TO dim-1 DO
  1420. size := size * a[i];
  1421. END;
  1422. RETURN size*staticElements;
  1423. END GetSize;
  1424. PROCEDURE SetSizes(dest: UnsafeArray);
  1425. VAR i: SIZE;
  1426. BEGIN
  1427. FOR i := 0 TO dim-1 DO
  1428. dest.len[i] := a[dim-1-i];
  1429. END;
  1430. END SetSizes;
  1431. BEGIN
  1432. (* static elements is requred for this case : POINTER TO ARRAY OF ARRAY X OF RecordWithPointer *)
  1433. dim := LEN( a,0 );
  1434. IF tag = NIL THEN
  1435. NewSys(p, GetSize() * elementSize + dim * SIZEOF(ADDRESS) + 3 *SIZEOF(ADDRESS) + (dim DIV 2) * 2 * SIZEOF(ADDRESS), FALSE);
  1436. ELSE
  1437. NewArr(p, tag, GetSize(), dim, FALSE);
  1438. END;
  1439. SetSizes(p);
  1440. SetPC(p);
  1441. dest := p;
  1442. IF (currentGeneration = Young) OR (youngCounts > 0) THEN
  1443. EnterInCardSet(ADDRESS OF dest);
  1444. END;
  1445. END NewArray;
  1446. (* obsolete for generic object file / required only for old loader *)
  1447. PROCEDURE FillStaticType*(VAR staticTypeAddr: ADDRESS; startAddr, typeInfoAdr: ADDRESS; size, recSize: SIZE;
  1448. numPtrs, numSlots: LONGINT);
  1449. VAR p, offset: ADDRESS; staticTypeBlock {UNTRACED}: StaticTypeBlock;
  1450. BEGIN
  1451. Machine.Acquire(Machine.Heaps);
  1452. Machine.Fill32(startAddr, size, 0); (* clear whole static type, size MOD AddressSize = 0 implicitly, see WriteType in PCOF.Mod *)
  1453. SYSTEM.PUT(startAddr, MethodEndMarker); (* sentinel *)
  1454. (* methods and tags filled in later *)
  1455. offset := AddressSize * (numSlots + 1 + 1); (* #methods, max. no. of tags, method end marker (sentinel), pointer to type information*)
  1456. p := startAddr + offset;
  1457. SYSTEM.PUT(p + TypeDescOffset, typeInfoAdr); (* pointer to typeInfo *)
  1458. staticTypeBlock := SYSTEM.VAL(StaticTypeBlock, p);
  1459. staticTypeBlock.recSize := recSize;
  1460. staticTypeAddr := p;
  1461. (* create the pointer for the dynamic array of pointer offsets, the dynamic array of pointer offsets is stored in the static type
  1462. descriptor, it has no header part *)
  1463. INC(p, SIZEOF(StaticTypeDesc));
  1464. IF p MOD (2 * AddressSize) # 0 THEN INC(p, AddressSize) END;
  1465. SYSTEM.PUT(p + 3 * AddressSize, numPtrs); (* internal structure of dynamic array without pointers: the first 3 fields are unused *)
  1466. staticTypeBlock.pointerOffsets := SYSTEM.VAL(PointerOffsets, p); (* the fourth field contains the dimension of the array *)
  1467. (* pointer offsets filled in later *)
  1468. Machine.Release(Machine.Heaps)
  1469. END FillStaticType;
  1470. PROCEDURE AddFinalizer*(obj: ANY; n: FinalizerNode);
  1471. BEGIN
  1472. n.objWeak := obj; n.objStrong := NIL; n.finalizerStrong := NIL;
  1473. Refer(obj); (* make sure this object is not removed via reference counting *)
  1474. Machine.Acquire(Machine.Heaps);
  1475. n.nextFin := checkRoot; checkRoot := n;
  1476. IF Stats THEN INC(NfinalizeAlive) END;
  1477. Machine.Release(Machine.Heaps)
  1478. END AddFinalizer;
  1479. (** Compute total heap size, free space and largest free block size in bytes. This is a slow operation. *)
  1480. PROCEDURE GetHeapInfo*(VAR total, free, largest: SIZE);
  1481. VAR memBlock {UNTRACED}: Machine.MemoryBlock; blockAdr: ADDRESS;
  1482. block {UNTRACED}: HeapBlock;
  1483. BEGIN
  1484. Machine.Acquire(Machine.Heaps);
  1485. memBlock := Machine.memBlockHead;
  1486. total := 0; free := 0; largest := 0;
  1487. WHILE memBlock # NIL DO
  1488. total := total + memBlock.endBlockAdr - memBlock.beginBlockAdr;
  1489. blockAdr := memBlock.beginBlockAdr;
  1490. WHILE blockAdr < memBlock.endBlockAdr DO
  1491. block := SYSTEM.VAL(HeapBlock, blockAdr + BlockHeaderSize); (* get heap block *)
  1492. IF (block.mark < currentMarkValue) THEN (* free/unused block encountered *)
  1493. free := free + block.size;
  1494. IF ADDRESS(block.size) > ADDRESS(largest) THEN largest := block.size END
  1495. END;
  1496. blockAdr := blockAdr + block.size;
  1497. END;
  1498. memBlock := memBlock.next
  1499. END;
  1500. Machine.Release(Machine.Heaps)
  1501. END GetHeapInfo;
  1502. PROCEDURE DecRefCount(VAR count: WORD): BOOLEAN;
  1503. VAR value: WORD;
  1504. BEGIN
  1505. LOOP
  1506. value := CAS (count,0,0);
  1507. ASSERT(value > 0);
  1508. IF CAS (count, value, value-1) = value THEN RETURN value =1 END;
  1509. END;
  1510. END DecRefCount;
  1511. PROCEDURE RefCount*(p: DataBlockU): WORD;
  1512. BEGIN
  1513. RETURN p.heapBlock.refCount;
  1514. END RefCount;
  1515. (** Mark - Mark an object and its decendents. Used by findRoots. *)
  1516. PROCEDURE RecursiveReset(h {UNTRACED}: HeapBlock);
  1517. VAR
  1518. orgBlock: ADDRESS;
  1519. staticTypeBlock {UNTRACED}: StaticTypeBlock;
  1520. currentArrayElemAdr, lastArrayElemAdr: ADDRESS; i: LONGINT;
  1521. protected {UNTRACED}: ProtRecBlock;
  1522. b {UNTRACED}: POINTER {UNSAFE} TO RECORD p: ANY END;
  1523. meta {UNTRACED }: POINTER {UNSAFE} TO RECORD staticTypeBlock {FICTIVE=TypeDescOffset}: StaticTypeBlock; last, current, first: ADDRESS END;
  1524. (* markStack {UNTRACED}: HeapBlockU; *)
  1525. first {UNTRACED}, last{UNTRACED}: HeapBlockU;
  1526. count: SIZE;
  1527. PROCEDURE EnterMe(d: DataBlockU);
  1528. VAR h: HeapBlockU
  1529. BEGIN
  1530. IF (d # NIL) THEN
  1531. h := d.heapBlock;
  1532. IF (h # NIL) & DecRefCount(h.refCount) THEN
  1533. INC(count);
  1534. h.heapBlock := first;
  1535. (*
  1536. IF last = NIL THEN
  1537. first := h;
  1538. ELSE
  1539. last.heapBlock := h;
  1540. END;
  1541. last := h;
  1542. *)
  1543. first := h;
  1544. END;
  1545. END;
  1546. END EnterMe;
  1547. (* for queue
  1548. PROCEDURE Get(): {UNTRACED} HeapBlock;
  1549. VAR h {UNTRACED}: HeapBlockU;
  1550. BEGIN
  1551. h := first;
  1552. IF h # NIL THEN
  1553. first := h.heapBlock;
  1554. IF first = NIL THEN last := NIL END;
  1555. END;
  1556. RETURN h;
  1557. END Get;
  1558. *)
  1559. BEGIN{UNCHECKED} (* omit any range checks etc.*)
  1560. (* all blocks remain visible from the GC until the reference count is set to -1 *)
  1561. first := NIL; last := NIL;
  1562. (*EnterMe(p);*)
  1563. h.heapBlock := NIL;
  1564. first := h;
  1565. (* misuse markstack for stack of objects to reset
  1566. objects on this stack are already free by reference counting but the GC still sees them and does not collect them
  1567. *)
  1568. WHILE (first # NIL) DO
  1569. (*
  1570. h := Get();
  1571. *)
  1572. h := first;
  1573. first := h.heapBlock;
  1574. meta := h.dataAdr;
  1575. staticTypeBlock := meta.staticTypeBlock;
  1576. IF staticTypeBlock # NIL THEN
  1577. orgBlock := h.dataAdr;
  1578. IF ~(h IS ArrayBlock) THEN
  1579. FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
  1580. b := orgBlock + staticTypeBlock.pointerOffsets[i];
  1581. EnterMe(b.p);
  1582. END
  1583. ELSE
  1584. currentArrayElemAdr := meta.first;
  1585. lastArrayElemAdr := meta.first + meta.last * staticTypeBlock.recSize;
  1586. WHILE currentArrayElemAdr < lastArrayElemAdr DO
  1587. FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
  1588. b := currentArrayElemAdr + staticTypeBlock.pointerOffsets[i];
  1589. EnterMe(b.p);
  1590. END;
  1591. INC(currentArrayElemAdr, staticTypeBlock.recSize);
  1592. END
  1593. END;
  1594. IF h IS ProtRecBlock THEN
  1595. protected := h(ProtRecBlock);
  1596. EnterMe(protected.awaitingLock.head);
  1597. EnterMe(protected.awaitingCond.head);
  1598. EnterMe(protected.lockedBy);
  1599. EnterMe(protected.lock);
  1600. END;
  1601. END;
  1602. h.refCount := -1;
  1603. END;
  1604. (*
  1605. ASSERT(CheckPointer(p));
  1606. meta := p;
  1607. staticTypeBlock := meta.staticTypeBlock;
  1608. IF staticTypeBlock = NIL THEN RETURN END; (* no outgoing pointers *)
  1609. orgHeapBlock := p.heapBlock;
  1610. orgBlock := p;
  1611. IF ~(orgHeapBlock IS ArrayBlock) THEN
  1612. FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
  1613. b := orgBlock + staticTypeBlock.pointerOffsets[i];
  1614. Reset(b.p)
  1615. END
  1616. ELSE
  1617. currentArrayElemAdr := meta.first;
  1618. lastArrayElemAdr := meta.first + meta.last * staticTypeBlock.recSize;
  1619. WHILE currentArrayElemAdr < lastArrayElemAdr DO
  1620. FOR i := 0 TO LEN(staticTypeBlock.pointerOffsets) - 1 DO
  1621. b := currentArrayElemAdr + staticTypeBlock.pointerOffsets[i];
  1622. Reset(b.p)
  1623. END;
  1624. INC(currentArrayElemAdr, staticTypeBlock.recSize);
  1625. END
  1626. END;
  1627. IF orgHeapBlock IS ProtRecBlock THEN
  1628. protected := orgHeapBlock(ProtRecBlock);
  1629. Reset(protected.awaitingLock.head);
  1630. Reset(protected.awaitingCond.head);
  1631. Reset(protected.lockedBy);
  1632. Reset(protected.lock);
  1633. END;
  1634. *)
  1635. END RecursiveReset;
  1636. PROCEDURE Reset*(old: DataBlockU);
  1637. BEGIN
  1638. INC(resets);
  1639. IF (old # NIL) & (old.heapBlock # NIL) THEN
  1640. ASSERT(old - old.heapBlock < 256);
  1641. IF DecRefCount(old.heapBlock.refCount) THEN
  1642. RecursiveReset(old.heapBlock);
  1643. (*old.heapBlock.refCount := -1;*)
  1644. END;
  1645. END;
  1646. END Reset;
  1647. PROCEDURE ResetMathArray*(p: POINTER {UNTRACED,UNSAFE} TO RECORD p: ADDRESS END);
  1648. BEGIN
  1649. IF p # NIL THEN
  1650. Reset(p.p);
  1651. END;
  1652. END ResetMathArray;
  1653. PROCEDURE ResetRecord*(src: ADDRESS; tag: StaticTypeBlockU);
  1654. VAR i: SIZE;sval: ADDRESS;
  1655. BEGIN
  1656. FOR i := 0 TO LEN(tag.pointerOffsets)-1 DO
  1657. SYSTEM.GET(src+tag.pointerOffsets[i], sval);
  1658. Reset(sval);
  1659. END;
  1660. END ResetRecord;
  1661. PROCEDURE ResetArray*(src: ADDRESS; tag: StaticTypeBlockU; numElems: SIZE);
  1662. VAR i, j: SIZE; sval: ADDRESS;
  1663. BEGIN
  1664. FOR j := 0 TO LEN(tag.pointerOffsets)-1 DO
  1665. FOR i := 0 TO numElems-1 DO
  1666. SYSTEM.GET(src+ i * tag.recSize + tag.pointerOffsets[j], sval);
  1667. Reset(sval);
  1668. END;
  1669. END;
  1670. END ResetArray;
  1671. PROCEDURE Refer*(old: DataBlockU);
  1672. BEGIN
  1673. INC(refers);
  1674. IF (old # NIL) & (old.heapBlock # NIL) THEN
  1675. ASSERT(old - old.heapBlock < 256);
  1676. Machine.AtomicInc(old.heapBlock.refCount);
  1677. END;
  1678. END Refer;
  1679. PROCEDURE ReferMathArray*(p: POINTER {UNTRACED,UNSAFE} TO RECORD p: ADDRESS END);
  1680. BEGIN
  1681. IF p # NIL THEN
  1682. Refer(p.p);
  1683. END;
  1684. END ReferMathArray;
  1685. PROCEDURE ReferRecord*(src: ADDRESS; tag: StaticTypeBlockU);
  1686. VAR i: SIZE;sval: ADDRESS;
  1687. BEGIN
  1688. FOR i := 0 TO LEN(tag.pointerOffsets)-1 DO
  1689. SYSTEM.GET(src+tag.pointerOffsets[i], sval);
  1690. Refer(sval);
  1691. END;
  1692. END ReferRecord;
  1693. PROCEDURE ReferArray*(src: ADDRESS; tag: StaticTypeBlockU; numElems: SIZE);
  1694. VAR i, j: SIZE; sval: ADDRESS;
  1695. BEGIN
  1696. FOR j := 0 TO LEN(tag.pointerOffsets)-1 DO
  1697. FOR i := 0 TO numElems-1 DO
  1698. SYSTEM.GET(src+i * tag.recSize + tag.pointerOffsets[j], sval);
  1699. Refer(sval);
  1700. END;
  1701. END;
  1702. END ReferArray;
  1703. PROCEDURE CheckInternalAssignment(dest, src: DataBlockU);
  1704. VAR old: DataBlockU;
  1705. BEGIN
  1706. INC(assigns);
  1707. IF (src # NIL) & (src.heapBlock # NIL) THEN
  1708. ASSERT(src - src.heapBlock < 256);
  1709. Machine.AtomicInc(src.heapBlock.refCount);
  1710. END;
  1711. SYSTEM.GET(dest, old);
  1712. Reset(old);
  1713. (*IF (old # NIL) & (old.heapBlock # NIL) THEN
  1714. IF (old - old.heapBlock < 256) THEN
  1715. Machine.AtomicDec(old.heapBlock.refCount);
  1716. IF (old.heapBlock.refCount < 0) THEN TRACE(old.heapBlock.refCount);HALT(100); GetPCs(); END;
  1717. ELSE
  1718. TRACE(old, old.heapBlock, old-old.heapBlock);
  1719. HALT(100);
  1720. GetPCs();
  1721. END;
  1722. END;
  1723. *)
  1724. END CheckInternalAssignment;
  1725. PROCEDURE CheckAssignment*(dest, src: DataBlockU);
  1726. BEGIN
  1727. (*IF (currentGeneration = Young) OR (youngCounts > 0) THEN*)
  1728. CheckInternalAssignment(dest, src);
  1729. (*END;*)
  1730. END CheckAssignment;
  1731. PROCEDURE Assign*(VAR dest: ADDRESS; src: ADDRESS);
  1732. BEGIN
  1733. CheckInternalAssignment(ADDRESS OF dest,src);
  1734. dest := src;
  1735. END Assign;
  1736. PROCEDURE AssignRecord*(dest: ADDRESS; tag: StaticTypeBlockU; src: ADDRESS);
  1737. VAR i: SIZE; sval: ADDRESS;
  1738. BEGIN
  1739. FOR i := 0 TO LEN(tag.pointerOffsets)-1 DO
  1740. SYSTEM.GET(src+tag.pointerOffsets[i], sval);
  1741. CheckInternalAssignment(dest + tag.pointerOffsets[i], sval);
  1742. END;
  1743. SYSTEM.MOVE(src,dest,tag.recSize);
  1744. END AssignRecord;
  1745. PROCEDURE AssignArray*(dest: ADDRESS; tag: StaticTypeBlockU; numElems: SIZE; src: ADDRESS);
  1746. VAR i, j: SIZE; sval,offset: ADDRESS;
  1747. BEGIN
  1748. FOR j := 0 TO LEN(tag.pointerOffsets)-1 DO
  1749. FOR i := 0 TO numElems-1 DO
  1750. offset := i * tag.recSize + tag.pointerOffsets[j];
  1751. SYSTEM.GET(src+offset, sval);
  1752. CheckInternalAssignment(dest+ offset, sval);
  1753. END;
  1754. END;
  1755. SYSTEM.MOVE(src,dest,tag.recSize * numElems);
  1756. END AssignArray;
  1757. (* NilGC - Default garbage collector. *)
  1758. PROCEDURE NilGC;
  1759. BEGIN
  1760. HALT(301) (* garbage collector not available yet *)
  1761. END NilGC;
  1762. (* Init - Initialize the heap. *)
  1763. PROCEDURE Init;
  1764. VAR beginBlockAdr, endBlockAdr, freeBlockAdr, p: ADDRESS;
  1765. heapBlock: HeapBlockU; freeBlock: FreeBlockU; memBlock {UNTRACED}: Machine.MemoryBlock;
  1766. s: ARRAY 32 OF CHAR; minSize,i: LONGINT;
  1767. BEGIN
  1768. Machine.GetConfig("EnableFreeLists", s);
  1769. EnableFreeLists := (s[0] = "1");
  1770. Machine.GetConfig("EnableReturnBlocks", s);
  1771. EnableReturnBlocks := (s[0] = "1");
  1772. IF EnableReturnBlocks THEN Trace.String("Heaps:ReturnBlocks enabled"); Trace.Ln END;
  1773. Machine.GetConfig("TraceHeaps",s);
  1774. trace := (s[0] = "1");
  1775. minSize := 32;
  1776. FOR i := 0 TO MaxFreeLists DO
  1777. freeLists[i].minSize := minSize;
  1778. freeLists[i].first := NIL; freeLists[i].last := NIL;
  1779. IF i < FreeListBarrier THEN INC( minSize, BlockSize ) ELSE minSize := 2 * minSize END
  1780. END;
  1781. GC := NilGC;
  1782. newSum := 0;
  1783. checkRoot := NIL; finalizeRoot := NIL; rootList := NIL; realtimeList := NIL;
  1784. gcStatus := NIL;
  1785. Machine.SetGCParams;
  1786. Machine.GetStaticHeap(beginBlockAdr, endBlockAdr, freeBlockAdr);
  1787. (* the Type desciptor is generated by the compiler, therefore the linker does not have to patch anything any more *)
  1788. freeBlockTag := SYSTEM.TYPECODE (FreeBlockDesc);
  1789. systemBlockTag := SYSTEM.TYPECODE (SystemBlockDesc);
  1790. recordBlockTag := SYSTEM.TYPECODE (RecordBlockDesc);
  1791. protRecBlockTag := SYSTEM.TYPECODE (ProtRecBlockDesc);
  1792. arrayBlockTag := SYSTEM.TYPECODE (ArrayBlockDesc);
  1793. (* find last block in static heap *)
  1794. p := beginBlockAdr;
  1795. heapBlock := SYSTEM.VAL(HeapBlock, p + BlockHeaderSize);
  1796. WHILE p < freeBlockAdr DO
  1797. initBlock := SYSTEM.VAL(ANY, heapBlock.dataAdr);
  1798. p := p + heapBlock.size;
  1799. heapBlock := SYSTEM.VAL(HeapBlock, p + BlockHeaderSize)
  1800. END;
  1801. ASSERT(p = freeBlockAdr);
  1802. IF endBlockAdr - freeBlockAdr > 0 THEN
  1803. (* initialization of free heap block done here since boot file is only written up to freeBlockAdr *)
  1804. freeBlock := freeBlockAdr + BlockHeaderSize;
  1805. InitFreeBlock(freeBlock, Unmarked, NilVal, endBlockAdr - freeBlockAdr);
  1806. IF EnableFreeLists THEN AppendFreeBlock(freeBlock) END;
  1807. ASSERT(freeBlock.size MOD BlockSize = 0)
  1808. END;
  1809. currentMarkValue := GenerationMask;
  1810. currentGeneration := Old;
  1811. FOR i := 0 TO currentGeneration DO
  1812. generationMarkValues[i] := currentMarkValue;
  1813. END;
  1814. (* extend the heap for one block such that module initialization can continue as long as Heaps.GC is not set validly *)
  1815. Machine.ExpandHeap(1, 1, memBlock, beginBlockAdr, endBlockAdr); (* try = 1, size = 1 -> the minimal heap block expansion is performed *)
  1816. IF endBlockAdr > beginBlockAdr THEN
  1817. freeBlock := beginBlockAdr + BlockHeaderSize;
  1818. InitFreeBlock(freeBlock, Unmarked, NilVal, endBlockAdr - beginBlockAdr);
  1819. Machine.SetMemoryBlockEndAddress(memBlock, endBlockAdr);
  1820. IF EnableFreeLists THEN AppendFreeBlock(freeBlock) END;
  1821. sweepMarkValue := currentMarkValue;
  1822. sweepMemBlock := memBlock;
  1823. sweepBlockAdr := beginBlockAdr
  1824. END;
  1825. END Init;
  1826. PROCEDURE SetYoung*;
  1827. BEGIN
  1828. Machine.Acquire(Machine.Heaps);
  1829. currentGeneration := Young;
  1830. Machine.Release(Machine.Heaps);
  1831. END SetYoung;
  1832. PROCEDURE SetOld*;
  1833. BEGIN
  1834. Machine.Acquire(Machine.Heaps);
  1835. currentGeneration := Old;
  1836. Machine.Release(Machine.Heaps);
  1837. END SetOld;
  1838. PROCEDURE SetHeuristic*;
  1839. BEGIN
  1840. GCType := HeuristicStackInspectionGC;
  1841. Trace.String("GC mode : heuristic"); Trace.Ln;
  1842. END SetHeuristic;
  1843. PROCEDURE SetMetaData*;
  1844. BEGIN
  1845. GCType := MetaDataForStackGC;
  1846. Trace.String("GC mode : metadata"); Trace.Ln;
  1847. END SetMetaData;
  1848. BEGIN
  1849. (* The meta data stack inspection is more efficient than the heuristics *)
  1850. GCType := HeuristicStackInspectionGC;
  1851. Init;
  1852. END Heaps.
  1853. (*
  1854. TraceHeap:
  1855. 0 1 NR NEW record
  1856. 1 2 NA/NV NEW array
  1857. 2 4 NS SYSTEM.NEW
  1858. 3 8 DR deallocate record #
  1859. 4 16 DA deallocate array #
  1860. 5 32 DS deallocate sysblk #
  1861. 6 64 NT NewType
  1862. 7 128
  1863. 8 256 FB show free blocks #
  1864. 9 512 DP deallocate protrec #
  1865. 10 1024 finalizers
  1866. 11 2048 live/dead #
  1867. 12 4096 trace mark stack overflows #
  1868. # influences timing
  1869. *)
  1870. (*
  1871. 20.03.1998 pjm Started
  1872. 17.08.1998 pjm FindRoots method
  1873. 18.08.1998 pjm findPossibleRoots removed, use FindRoots method
  1874. 09.10.1998 pjm NewRec with page alignment
  1875. 21.01.1999 pjm Mark adapted for AosBuffers
  1876. 26.01.1999 pjm Incorporated changes for new compiler
  1877. 10.11.2000 pjm Finalizers
  1878. 26.01.2001 pjm Removed trapReserve, reimplemented NewBlock
  1879. 11.11.2004 lb Garbage collector with marking stack
  1880. 19.06.2007 ug Garbage collector using meta data for stack inspection (cf. Objects)
  1881. 11.07.2008 ug new heap data structures and adaption to GC
  1882. *)
  1883. Co
  1884. Compiler.Compile -p=Win32 --writeBarriers --traceModule=Trace
  1885. I386.Builtins.Mod Trace.Mod Windows.I386.Kernel32.Mod Windows.I386.Machine.Mod Heaps.Mod
  1886. Modules.Mod Windows.I386.Objects.Mod Windows.Kernel.Mod KernelLog.Mod Plugins.Mod Streams.Mod Pipes.Mod
  1887. Commands.Mod I386.Reals.Mod Reflection.Mod
  1888. Windows.I386.Traps.Mod Windows.WinTrace.Mod Windows.StdIO.Mod Locks.Mod Windows.Clock.Mod Disks.Mod Files.Mod
  1889. Dates.Mod Strings.Mod UTF8Strings.Mod FileTrapWriter.Mod Caches.Mod DiskVolumes.Mod
  1890. OldDiskVolumes.Mod RAMVolumes.Mod DiskFS.Mod OldDiskFS.Mod OberonFS.Mod FATVolumes.Mod FATFiles.Mod
  1891. ISO9660Volumes.Mod ISO9660Files.Mod Windows.User32.Mod Windows.WinTrace.Mod Windows.ODBC.Mod
  1892. Windows.Shell32.Mod Windows.SQL.Mod Windows.WinFS.Mod RelativeFileSystem.Mod BitSets.Mod Diagnostics.Mod
  1893. StringPool.Mod ObjectFile.Mod GenericLinker.Mod Loader.Mod BootConsole.Mod
  1894. ~
  1895. Compiler.Compile -p=Win32 --traceModule=Trace --writeBarriers Heaps.Mod ~
  1896. Linker.Link --fileFormat=PE32 --fileName=A2.exe --extension=GofW --displacement=401000H Builtins Trace Kernel32 Machine Heaps Modules Objects Kernel KernelLog Streams Commands FIles WinFS Clock Dates Reals Strings Diagnostics BitSets StringPool ObjectFile GenericLinker Reflection Loader BootConsole ~
  1897. FSTools.CloseFiles A2.exe ~
  1898. Heaps.ShowCards
  1899. (* enable generational garbage collection *)
  1900. Heaps.SetYoung
  1901. (* disable generational garbage collection *)
  1902. Heaps.SetOld
  1903. Kernel.GC
  1904. System.ModuleState Heaps ~