Unix.Heaps.Mod 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137
  1. (* ETH Oberon, Copyright 2002 ETH Zuerich Institut fuer Computersysteme, ETH Zentrum, CH-8092 Zuerich.
  2. Refer to the "General ETH Oberon System Source License" contract available at: http://www.oberon.ethz.ch/ *)
  3. MODULE Heaps; (** AUTHOR "G.F."; PURPOSE "Heap management and garbage collector"; *)
  4. IMPORT S := SYSTEM, Trace, Unix, Machine;
  5. CONST
  6. Stats* = TRUE; (* maintain statistical counters *)
  7. AddrSize = SIZEOF( ADDRESS );
  8. SizeSize = SIZEOF( SIZE );
  9. FlagsOfs = AddrSize * 3; (* flags offset in TypeDesc *)
  10. ModOfs* = AddrSize * 4; (* moduleAdr offset in TypeDesc *)
  11. (* TypeNameOfs = AddrSize * 5; (* type name offset in TypeDesc *)
  12. ModNameOfs = AddrSize * 2; (* module name offset in ModuleDesc *)
  13. *)
  14. NilVal* = 0;
  15. MethodEndMarker* = -40000000H; (* marks the end of the method addresses, used in Info.ModuleDetails *)
  16. ArrayAlignment = 8;
  17. HeapBlockOffset* = - 2*AddrSize;
  18. TypeDescOffset* = -AddrSize;
  19. MaxMarkDepth = 8000;
  20. ThruputBarrier = Machine.MemBlockSize;
  21. (* ----------------- object finalization ------------------------------*)
  22. TYPE
  23. Finalizer* = PROCEDURE {DELEGATE}( obj: ANY );
  24. FinalizerNode* = POINTER TO RECORD
  25. objWeak*{UNTRACED}: ANY; (* weak reference to checked object *)
  26. markAdr: ADDRESS; (* address of type tag of object *)
  27. nextFin: FinalizerNode; (* in finalization list *)
  28. objStrong*: ANY; (* strong reference to object to be finalized *)
  29. finalizer*{UNTRACED}: Finalizer; (* finalizer, if any *)
  30. finalizerStrong: Finalizer (* strong ref. to the obj that is referenced by the finalyzer, if any *)
  31. END;
  32. VAR
  33. checkRoot: FinalizerNode; (* list of checked objects (contains weak references to the checked objects) *)
  34. finalizeRoot: FinalizerNode; (* objects scheduled for finalization (contains references to scheduled objects) *)
  35. (* ------------------------- Heap ------------------------------- *)
  36. CONST
  37. BlockSize = 32;
  38. MaxFreeLists = 14; (* number of free lists *)
  39. FreeListBarrier = 7;
  40. MaxCandidates = 1024;
  41. ProtOfs = (AddrSize DIV 4)*(2*BlockSize) + 16; (*! p mod 32 = 16 ! *)
  42. SysOfs = 24; (*! p mod 16 = 8 ! *)
  43. ProtTypeBit* = 31; (** flags in TypeDesc, low bits reserved for extLevel *)
  44. TYPE
  45. FreeBlock = POINTER TO RECORD
  46. tag: ADDRESS; (* = ADDRESSOF( size ) *)
  47. size: SIZE;
  48. next{UNTRACED}: FreeBlock;
  49. END;
  50. FreeList = RECORD
  51. minSize: SIZE;
  52. first{UNTRACED}: FreeBlock;
  53. last{UNTRACED}: FreeBlock
  54. END;
  55. ProcessQueue* = RECORD
  56. head*, tail*: ANY
  57. END;
  58. ProtRecBlock* = POINTER TO ProtRecBlockDesc;
  59. ProtRecBlockDesc* = RECORD
  60. recSize-: SIZE; (* needed by procedure SizeOf(blk) *)
  61. awaitingLock* : ProcessQueue; (* unused in UnixAos *)
  62. awaitingCond* : ProcessQueue;
  63. lockedBy*: ANY;
  64. lock*: ANY; (* used by Win32, unused for I386 and UnixAos *)
  65. mtx*: Unix.Mutex_t; (* processes blocked awaiting lock (UnixAos only) *)
  66. enter*: Unix.Condition_t; (* processes blocked awaiting lock (UnixAos only) *)
  67. END;
  68. RootObject* = OBJECT
  69. PROCEDURE FindRoots*; (** abstract *)
  70. BEGIN HALT( 301 ) END FindRoots;
  71. END RootObject;
  72. StaticTypeBlock* = POINTER TO StaticTypeDesc;
  73. StaticTypeDesc = RECORD
  74. recSize: SIZE;
  75. pointerOffsets* {UNTRACED}: PointerOffsets;
  76. END;
  77. PointerOffsets = POINTER TO ARRAY OF SIZE;
  78. CandBuffer = ARRAY MaxCandidates OF ADDRESS;
  79. VAR
  80. freeLists: ARRAY MaxFreeLists + 1 OF FreeList;
  81. candidates: CandBuffer;
  82. nofcand: LONGINT;
  83. deferred: ARRAY 1000 OF ADDRESS;
  84. noDeferred: LONGINT;
  85. heapSize, heapAvailable: SIZE;
  86. shrinkDisabled: BOOLEAN;
  87. thruput: SIZE;
  88. GC* : PROCEDURE;
  89. InvokeGC* : PROCEDURE;
  90. collecting-: BOOLEAN;
  91. markDepth: LONGINT;
  92. saveSP* : PROCEDURE; (* save SP for usage in Objects.Process.FindRoots() *)
  93. (** Statistics. Will only be maintained if Stats = TRUE *)
  94. (** Memory allocation statistics *)
  95. Nnew- : LONGINT; (** Number of times NewBlock has been called since system startup *)
  96. NnewBytes- : HUGEINT; (** Number of bytes allocated by NewBlock since system startup *)
  97. (** Garbage collection statistics *)
  98. Ngc- : LONGINT; (** Number of GC cycles since system startup *)
  99. (** Statistics considering the last GC cyle *)
  100. Nmark-, Nmarked-, NfinalizeAlive-, NfinalizeDead-: LONGINT;
  101. NgcCyclesMark-, NgcCyclesLastRun-, NgcCyclesMax-, NgcCyclesAllRuns- : HUGEINT;
  102. PROCEDURE EmptyProc;
  103. END EmptyProc;
  104. (* ----------------- object finalization ---------------------------*)
  105. PROCEDURE AddFinalizer*( obj: ANY; n: FinalizerNode );
  106. VAR adr: ADDRESS;
  107. BEGIN
  108. n.objWeak := obj; n.objStrong := NIL; n.finalizerStrong := NIL;
  109. adr := S.VAL( ADDRESS, obj );
  110. IF ODD( adr DIV 8 ) THEN (* indirect tag *)
  111. S.GET( adr - AddrSize, adr );
  112. ELSIF ODD( adr DIV 16 ) THEN (* protected object *)
  113. adr := adr - ProtOfs
  114. END;
  115. n.markAdr := adr - AddrSize;
  116. Machine.Acquire( Machine.Heaps );
  117. n.nextFin := checkRoot; checkRoot := n;
  118. Machine.Release( Machine.Heaps )
  119. END AddFinalizer;
  120. (* Check reachability of finalized objects. *)
  121. PROCEDURE CheckFinalizedObjects;
  122. VAR n, p, t: FinalizerNode; tag: ADDRESS;
  123. PROCEDURE MarkDelegate( p: Finalizer );
  124. VAR pointer: ANY;
  125. BEGIN
  126. S.GET( ADDRESSOF( p ) + AddrSize, pointer );
  127. IF pointer # NIL THEN Mark( pointer ) END
  128. END MarkDelegate;
  129. BEGIN
  130. n := checkRoot;
  131. WHILE n # NIL DO (* move unmarked checked objects to finalize list *)
  132. S.GET( n.markAdr, tag );
  133. IF ~ODD( tag ) THEN (* not marked *)
  134. IF n = checkRoot THEN checkRoot := n.nextFin ELSE p.nextFin := n.nextFin END;
  135. n.objStrong := n.objWeak; (* anchor the object for finalization *)
  136. n.finalizerStrong := n.finalizer; (* anchor the finalizer for finalization *)
  137. t := n.nextFin; n.nextFin := finalizeRoot; finalizeRoot := n; n := t;
  138. IF Stats THEN DEC(NfinalizeAlive); INC(NfinalizeDead) END
  139. ELSE p := n; n := n.nextFin
  140. END
  141. END;
  142. (* now trace the weak references to keep finalized objects alive during this collection *)
  143. n := finalizeRoot;
  144. WHILE n # NIL DO
  145. MarkDelegate( n.finalizerStrong );
  146. Mark( n.objStrong ); n := n.nextFin
  147. END;
  148. n := checkRoot;
  149. WHILE n # NIL DO (* list of objects that had been marked before entering CheckFinalizedObjects *)
  150. (* we still have to mark the weak finalizers, as they might have not been marked before *)
  151. MarkDelegate( n.finalizer ); n := n.nextFin
  152. END;
  153. END CheckFinalizedObjects;
  154. (** Return the next scheduled finalizer or NIL if none available. Called by finalizer object in AosKernel. *)
  155. PROCEDURE GetFinalizer*( ): FinalizerNode;
  156. VAR n: FinalizerNode;
  157. BEGIN
  158. n := NIL;
  159. IF finalizeRoot # NIL THEN
  160. Machine.Acquire( Machine.Heaps );
  161. n := finalizeRoot; (* take one finalizer *)
  162. IF n # NIL THEN
  163. finalizeRoot := n.nextFin; n.nextFin := NIL;
  164. IF Stats THEN DEC(NfinalizeDead) END;
  165. END;
  166. Machine.Release( Machine.Heaps );
  167. END;
  168. RETURN n
  169. END GetFinalizer;
  170. (** Check finalizers registered in the specified module, which is about to be freed or shut down.
  171. Remove all finalizer procedures in this module from the finalizer lists so they won't be called any more. *)
  172. PROCEDURE CleanupModuleFinalizers*( codeAdr: ADDRESS; codeLen: SIZE; CONST name: ARRAY OF CHAR );
  173. VAR n, p, t: FinalizerNode; codeEnd: ADDRESS; N1, N2: LONGINT;
  174. BEGIN
  175. codeEnd := codeAdr + codeLen; N1 := 0; N2 := 0;
  176. Machine.Acquire( Machine.Heaps );
  177. n := checkRoot;
  178. WHILE n # NIL DO (* iterate over checked list *)
  179. t := n; n := n.nextFin;
  180. IF (codeAdr <= S.VAL( ADDRESS, t.finalizer )) & (S.VAL( ADDRESS, t.finalizer ) <= codeEnd ) THEN
  181. IF t = checkRoot THEN checkRoot := t.nextFin ELSE p.nextFin := t.nextFin END;
  182. IF Stats THEN DEC(NfinalizeAlive) END;
  183. INC( N1 )
  184. ELSE
  185. p := t
  186. END
  187. END;
  188. (* also remove finalizers from list, so they won't be called *)
  189. n := finalizeRoot;
  190. WHILE n # NIL DO (* iterate over finalized list *)
  191. t := n; n := n.nextFin;
  192. IF (codeAdr <= S.VAL( ADDRESS, t.finalizer ) ) & (S.VAL( ADDRESS, t.finalizer ) <= codeEnd ) THEN
  193. IF t = finalizeRoot THEN finalizeRoot := t.nextFin ELSE p.nextFin := t.nextFin END;
  194. IF Stats THEN DEC(NfinalizeDead) END;
  195. INC( N2 )
  196. ELSE
  197. p := t
  198. END
  199. END;
  200. Machine.Release( Machine.Heaps );
  201. IF (N1 # 0) OR (N2 # 0) THEN
  202. Machine.Acquire ( Machine.TraceOutput );
  203. Trace.String( name ); Trace.Char( " " );
  204. Trace.Int( N1, 1 ); Trace.String( " discarded finalizers, " );
  205. Trace.Int( N2, 1 ); Trace.StringLn( " pending finalizers" );
  206. Machine.Release ( Machine.TraceOutput );
  207. END
  208. END CleanupModuleFinalizers;
  209. (* 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. *)
  210. PROCEDURE AddRootObject*( rootObject: RootObject );
  211. BEGIN
  212. Mark( rootObject )
  213. (* IF rootObject = NIL THEN (* nothing *)
  214. ELSIF CheckPointer(SYSTEM.VAL(ADDRESS,rootObject)) THEN
  215. (* object in heap, must be fully marked and traversed *)
  216. Mark(rootObject)
  217. ELSE
  218. (* object in bootfile, traverse as root object only *)
  219. rootObject.nextRoot := rootList; rootList := rootObject; (* link root list *)
  220. END *)
  221. END AddRootObject;
  222. (* ------------------------- garbage collector ----------------------- *)
  223. PROCEDURE UnmarkedObject( ptr: ANY ): BOOLEAN; (* FALSE: alredy marked or sysblock *)
  224. VAR addr, taddr: ADDRESS; tag: ADDRESS; sysblock: BOOLEAN;
  225. BEGIN
  226. IF ptr = NIL THEN RETURN FALSE END;
  227. addr := S.VAL( ADDRESS, ptr );
  228. IF ~ValidPointer( addr ) THEN RETURN FALSE END;
  229. sysblock := FALSE; taddr := addr - AddrSize;
  230. IF ODD( addr DIV 8 ) THEN (* sysblock *)
  231. taddr := taddr - SysOfs; sysblock := TRUE
  232. ELSIF ODD( addr DIV 16 ) THEN (* protected object *)
  233. taddr := taddr - ProtOfs;
  234. END;
  235. S.GET( taddr, tag );
  236. IF ODD( tag ) THEN
  237. (* already marked *) RETURN FALSE
  238. ELSE
  239. S.PUT( taddr, tag + 1 ); (* mark this block *) INC( Nmarked );
  240. IF sysblock THEN RETURN FALSE END;
  241. IF ptr IS RootObject THEN ptr(RootObject).FindRoots END;
  242. RETURN TRUE
  243. END;
  244. END UnmarkedObject;
  245. PROCEDURE MarkRecordFields( rec: ADDRESS; sTB: StaticTypeBlock );
  246. VAR ptr: ANY; i, n: SIZE;
  247. BEGIN
  248. n := LEN( sTB.pointerOffsets ); i := 0;
  249. WHILE i < n DO
  250. S.GET( rec + sTB.pointerOffsets[i], ptr );
  251. IF ptr # NIL THEN Mark( ptr ) END;
  252. INC( i )
  253. END
  254. END MarkRecordFields;
  255. PROCEDURE Mark*( ptr: ADDRESS );
  256. VAR
  257. cur, lastElem, tag: ADDRESS;
  258. sTB{UNTRACED}: StaticTypeBlock;
  259. BEGIN
  260. IF Stats THEN INC(Nmark) END;
  261. INC( markDepth );
  262. IF UnmarkedObject( S.VAL( ANY, ptr ) ) THEN
  263. S.GET( ptr - AddrSize, tag );
  264. sTB := S.VAL( StaticTypeBlock, tag DIV 4 * 4 );
  265. IF ODD( tag DIV 2 ) THEN (* array *)
  266. IF markDepth <= MaxMarkDepth - 10 THEN
  267. S.GET( ptr, lastElem );
  268. S.GET( ptr + 2*AddrSize, cur );
  269. REPEAT
  270. MarkRecordFields( cur, sTB );
  271. INC( cur, sTB.recSize );
  272. UNTIL cur > lastElem
  273. ELSE
  274. deferred[noDeferred] := ptr; INC( noDeferred );
  275. END;
  276. ELSE
  277. IF markDepth <= MaxMarkDepth THEN
  278. MarkRecordFields( ptr, sTB )
  279. ELSE
  280. deferred[noDeferred] := ptr; INC( noDeferred );
  281. END;
  282. END;
  283. END;
  284. DEC( markDepth );
  285. IF (markDepth <= 0) & (noDeferred > 0) THEN MarkDeferred END
  286. END Mark;
  287. PROCEDURE MarkDeferred;
  288. VAR
  289. ptr, cur, lastElem, tag: ADDRESS;
  290. sTB{UNTRACED}: StaticTypeBlock;
  291. BEGIN
  292. markDepth := 1;
  293. WHILE noDeferred > 0 DO
  294. DEC( noDeferred );
  295. ptr := deferred[noDeferred];
  296. S.GET( ptr - AddrSize, tag );
  297. sTB := S.VAL( StaticTypeBlock, tag DIV 4 * 4 );
  298. IF ODD( tag DIV 2 )THEN
  299. S.GET( ptr, lastElem );
  300. S.GET( ptr + 2*AddrSize, cur );
  301. REPEAT
  302. MarkRecordFields( cur, sTB );
  303. INC( cur, sTB.recSize );
  304. UNTIL cur > lastElem
  305. ELSE
  306. MarkRecordFields( ptr, sTB )
  307. END;
  308. END;
  309. END MarkDeferred;
  310. PROCEDURE AppendFree( VAR freeList: FreeList; block: FreeBlock );
  311. BEGIN
  312. IF freeList.first = NIL THEN
  313. freeList.first := block; freeList.last := block
  314. ELSE
  315. freeList.last.next := block;
  316. freeList.last := block;
  317. END;
  318. block.next := NIL
  319. END AppendFree;
  320. PROCEDURE InsertSorted( VAR freeList: FreeList; block: FreeBlock );
  321. VAR x: FreeBlock;
  322. BEGIN
  323. (* keep them ordered to avoid unnecessary splits *)
  324. (* this optimization has positive impact on heap utilization
  325. 130 MB vs. 240 MB heap for compiling and linking a new system
  326. but it slows down heap allocation speed. *)
  327. x := freeList.first;
  328. IF (x = NIL) OR (x.size > block.size) THEN
  329. block.next := x;
  330. freeList.first := block
  331. ELSE
  332. WHILE ( x.next # NIL) & (x.next.size < block.size) DO x := x.next END;
  333. block.next := x.next;
  334. x.next := block
  335. END
  336. END InsertSorted;
  337. PROCEDURE Recycle( blkAdr: ADDRESS; blkSize: SIZE );
  338. VAR i: LONGINT; block: FreeBlock;
  339. BEGIN
  340. (* ASSERT( blkSize MOD BlockSize = 0 ); *)
  341. block := S.VAL( FreeBlock, blkAdr );
  342. block.tag := blkAdr + AddrSize;
  343. block.size := blkSize - AddrSize;
  344. block.next := NIL;
  345. i := 0;
  346. WHILE (i < MaxFreeLists) & (freeLists[i+1].minSize < blkSize) DO INC( i ) END;
  347. IF i < FreeListBarrier THEN
  348. AppendFree( freeLists[i], block )
  349. ELSE
  350. InsertSorted( freeLists[i], block )
  351. END;
  352. INC( heapAvailable, blkSize );
  353. END Recycle;
  354. PROCEDURE ClearFreeLists;
  355. VAR i, minSize: LONGINT;
  356. BEGIN
  357. minSize := BlockSize;
  358. FOR i := 0 TO MaxFreeLists DO
  359. freeLists[i].minSize := minSize;
  360. freeLists[i].first := NIL;
  361. freeLists[i].last := NIL;
  362. IF i < FreeListBarrier THEN INC( minSize, BlockSize ) ELSE minSize := 2 * minSize END
  363. END;
  364. heapAvailable := 0
  365. END ClearFreeLists;
  366. PROCEDURE ShowFreeLists( CONST msg: ARRAY OF CHAR );
  367. VAR i, n: LONGINT; m: SIZE; b: FreeBlock; bad: BOOLEAN;
  368. BEGIN
  369. Trace.Ln;
  370. Trace.String( "==== FreeLists " ); Trace.String( msg ); Trace.Ln;
  371. FOR i := 0 TO MaxFreeLists DO
  372. Trace.Int( i, 2 ); Trace.Int( freeLists[i].minSize, 6 ); Trace.String( ": " );
  373. b := freeLists[i].first; n := 0; m := 0; bad := FALSE;
  374. IF i < FreeListBarrier THEN
  375. WHILE b # NIL DO INC( n ); b := b.next END;
  376. ELSE
  377. WHILE b # NIL DO
  378. INC( n );
  379. IF n < 20 THEN
  380. Trace.Int( b.size, 1 ); Trace.Char( ',' );
  381. IF n MOD 8 = 0 THEN Trace.Ln; Trace.String( " " ) END;
  382. END;
  383. IF b.size < m THEN bad := TRUE ELSE m := b.size END;
  384. b := b.next
  385. END;
  386. IF n > 0 THEN Trace.String( " largest=" ); Trace.Int( m, 0 ) END;
  387. IF bad THEN Trace.String( ", bad ordered" ) END
  388. END;
  389. Trace.String( " [" ); Trace.Int( n, 0 ); Trace.StringLn( "]" )
  390. END;
  391. Trace.Ln
  392. END ShowFreeLists;
  393. PROCEDURE Sweep;
  394. VAR
  395. block, freeBlock, endBlockAdr, tag: ADDRESS;
  396. blockSize, freeSize: SIZE;
  397. memBlock, nextMemBlock: Machine.MemoryBlock;
  398. BEGIN
  399. ClearFreeLists;
  400. heapAvailable := 0;
  401. memBlock := Machine.memBlockHead;
  402. WHILE memBlock # NIL DO
  403. block := memBlock.beginBlockAdr; endBlockAdr := memBlock.endBlockAdr;
  404. freeSize := 0;
  405. WHILE block < endBlockAdr DO
  406. blockSize := SizeOf( block );
  407. S.GET( block, tag );
  408. IF ~ODD( tag) THEN
  409. (* collect *)
  410. IF freeSize = 0 THEN freeBlock := block END;
  411. INC( freeSize, blockSize );
  412. ELSE
  413. S.PUT( block, tag - 1 ); (* remove mark bit *)
  414. IF freeSize > 0 THEN
  415. Recycle( freeBlock, freeSize );
  416. freeSize := 0
  417. END
  418. END;
  419. INC( block, blockSize );
  420. END;
  421. nextMemBlock := memBlock.next;
  422. IF (freeSize = endBlockAdr - memBlock.beginBlockAdr) THEN
  423. (* whole block is free, unlink it*)
  424. IF shrinkDisabled THEN
  425. Recycle( freeBlock, freeSize ); (* last collected block: *)
  426. ELSE
  427. Machine.FreeMemBlock( memBlock );
  428. heapSize := DetermineHeapSize()
  429. END
  430. ELSIF freeSize > 0 THEN
  431. Recycle( freeBlock, freeSize ); (* last collected block: *)
  432. END;
  433. memBlock := nextMemBlock;
  434. END;
  435. (* ShowFreeLists( "after Sweep" ) *)
  436. END Sweep;
  437. PROCEDURE SizeOf( block: ADDRESS ): SIZE;
  438. VAR tag, lastElem: ADDRESS; recSize, blockSize: SIZE;
  439. BEGIN
  440. S.GET( block, tag );
  441. S.GET( tag DIV 4 * 4, recSize );
  442. IF ODD( tag DIV 2 ) THEN (* array *)
  443. S.GET( block + AddrSize, lastElem );
  444. blockSize := lastElem + recSize - block
  445. ELSE
  446. blockSize := recSize + AddrSize
  447. END;
  448. INC( blockSize, (-blockSize) MOD BlockSize );
  449. RETURN blockSize
  450. END SizeOf;
  451. PROCEDURE CheckCandidates;
  452. VAR
  453. i, j, h, nc: LONGINT; mb: Machine.MemoryBlock;
  454. buffer: CandBuffer;
  455. cand, p, tag, tag2, block: ADDRESS;
  456. blkSize: SIZE;
  457. PROCEDURE NextCandidate(): ADDRESS;
  458. VAR cand: ADDRESS;
  459. BEGIN
  460. IF i < nc THEN cand := buffer[i]; INC( i ) ELSE cand := 0 END;
  461. RETURN cand
  462. END NextCandidate;
  463. BEGIN
  464. IF nofcand = 0 THEN RETURN END;
  465. buffer := candidates; nc := nofcand; nofcand := 0;
  466. (* sort buffer in increasing order using shellsort *)
  467. h := 1;
  468. REPEAT h := h*3 + 1 UNTIL h > nc;
  469. REPEAT
  470. h := h DIV 3; i := h;
  471. WHILE i < nc DO
  472. p := buffer[i]; j := i;
  473. WHILE (j >= h) & (buffer[j - h] > p) DO
  474. buffer[j] := buffer[j - h]; j := j - h
  475. END;
  476. buffer[j] := p; INC( i )
  477. END
  478. UNTIL h = 1;
  479. i := 0; cand := NextCandidate();
  480. mb := Machine.memBlockHead;
  481. REPEAT
  482. IF (cand < mb.endBlockAdr) & (buffer[nc-1] > mb.beginBlockAdr) THEN
  483. block := mb.beginBlockAdr;
  484. REPEAT
  485. blkSize := SizeOf( block );
  486. IF cand <= block + AddrSize THEN
  487. IF cand = block + AddrSize THEN
  488. S.GET( block, tag );
  489. IF tag = cand THEN (* free block *)
  490. ELSE (* record or array *) Mark( cand )
  491. END
  492. END;
  493. cand := NextCandidate( );
  494. ELSIF cand = block + AddrSize + SysOfs THEN (* sysblock ? *)
  495. IF blkSize > AddrSize + SysOfs THEN
  496. S.GET( block, tag ); S.GET( cand - AddrSize, tag2 );
  497. IF (tag2 = cand - SysOfs) & (tag2 = tag) THEN (* sysblock *) Mark( cand ) END;
  498. cand := NextCandidate( )
  499. ELSE
  500. block := block + blkSize
  501. END
  502. ELSIF cand = block + AddrSize + ProtOfs THEN (* protected record ? *)
  503. IF blkSize > AddrSize + ProtOfs THEN
  504. S.GET( block, tag );
  505. IF tag = block + AddrSize THEN (* protected record *) Mark( cand ) END;
  506. cand := NextCandidate( )
  507. ELSE
  508. block := block + blkSize
  509. END;
  510. ELSE
  511. block := block + blkSize
  512. END;
  513. UNTIL (cand = 0) OR (block >= mb.endBlockAdr) OR (cand >= mb.endBlockAdr);
  514. END;
  515. mb := mb.next;
  516. UNTIL (mb = NIL) OR (cand = 0);
  517. END CheckCandidates;
  518. PROCEDURE AddCandidate*( p: ADDRESS );
  519. VAR tag0Addr, tag0, tag: ADDRESS; i: LONGINT;
  520. BEGIN
  521. IF p MOD 32 = 0 THEN
  522. tag0Addr := p - AddrSize (* RecBlk, ArrBlk *)
  523. ELSIF p MOD 32 = 16 THEN
  524. tag0Addr := p - ProtOfs - AddrSize (* ProtRecBlk *)
  525. ELSIF p MOD 16 = 8 THEN
  526. tag0Addr := p - SysOfs - AddrSize (* SysBlk *)
  527. ELSE
  528. (* p is not a pointer *) RETURN
  529. END;
  530. i := 0;
  531. WHILE i < nofcand DO
  532. IF p = candidates[i] THEN (* double *) RETURN END;
  533. INC( i )
  534. END;
  535. IF ValidAddress( tag0Addr ) THEN
  536. S.GET( tag0Addr, tag0 );
  537. IF ODD( tag0 ) THEN (* already marked *) RETURN END;
  538. S.GET ( p - AddrSize, tag );
  539. IF ValidAddress( tag DIV 4 * 4 ) THEN
  540. candidates[nofcand] := p; INC( nofcand );
  541. IF nofcand = MaxCandidates THEN CheckCandidates END
  542. END;
  543. END
  544. END AddCandidate;
  545. PROCEDURE CollectGarbage*( root: RootObject );
  546. VAR time1, time2 : HUGEINT;
  547. BEGIN
  548. IF Stats THEN
  549. Nmark := 0; Nmarked := 0;
  550. INC( Ngc );
  551. time1 := Machine.GetTimer( );
  552. END;
  553. collecting := TRUE; markDepth := 0; noDeferred := 0; nofcand := 0;
  554. Mark( root );
  555. REPEAT CheckCandidates UNTIL nofcand = 0;
  556. CheckFinalizedObjects;
  557. Sweep;
  558. collecting := FALSE; thruput := 0;
  559. IF Stats THEN
  560. time2 := Machine.GetTimer( );
  561. NgcCyclesLastRun := time2 - time1;
  562. IF NgcCyclesLastRun > NgcCyclesMax THEN NgcCyclesMax := NgcCyclesLastRun END;
  563. INC( NgcCyclesAllRuns, NgcCyclesLastRun );
  564. NgcCyclesMark := NgcCyclesLastRun
  565. END;
  566. END CollectGarbage;
  567. (* -------------------------- memory allocation ----------------------- *)
  568. PROCEDURE FindFreeBlock( size: SIZE ): FreeBlock;
  569. VAR prev, block: FreeBlock; i: LONGINT;
  570. BEGIN
  571. i := 0;
  572. WHILE (i < MaxFreeLists) & (freeLists[i+1].minSize <= size) DO INC( i ) END;
  573. REPEAT
  574. block := freeLists[i].first;
  575. IF block # NIL THEN
  576. IF block.size + AddrSize >= size THEN
  577. IF block = freeLists[i].last THEN freeLists[i].first := NIL; freeLists[i].last := NIL
  578. ELSE freeLists[i].first := block.next; block.next := NIL
  579. END;
  580. ELSE (* i = MaxFreeLists *)
  581. REPEAT prev := block; block := block.next
  582. UNTIL (block = NIL) OR (block.size + AddrSize >= size);
  583. IF block # NIL THEN prev.next := block.next END
  584. END
  585. END;
  586. INC( i )
  587. UNTIL (block # NIL) OR (i > MaxFreeLists);
  588. RETURN block
  589. END FindFreeBlock;
  590. PROCEDURE Collect;
  591. BEGIN
  592. thruput := 0;
  593. Machine.Release( Machine.Heaps );
  594. GC;
  595. Machine.Acquire( Machine.Heaps );
  596. END Collect;
  597. PROCEDURE GetBlock( size: SIZE ): ADDRESS; (* size MOD B = 0 *)
  598. VAR
  599. block: FreeBlock; blkSize: SIZE; blkAdr, adr2: ADDRESS;
  600. BEGIN
  601. IF (thruput > ThruputBarrier) OR (heapAvailable < size) THEN Collect END;
  602. REPEAT
  603. block := FindFreeBlock( size );
  604. IF block = NIL THEN
  605. IF thruput > 0 THEN Collect
  606. ELSE
  607. (* ShowFreeLists( "befor ExpandHeap" ); *)
  608. Machine.ExpandHeap( 0, size, S.VAL( ADDRESS, block ), adr2 );
  609. IF block # NIL THEN
  610. heapSize := DetermineHeapSize();
  611. ELSE
  612. Trace.Ln;
  613. Trace.String( "Heapspace exhausted" ); Trace.Ln;
  614. Machine.Release( Machine.Heaps );
  615. HALT( 99 )
  616. END
  617. END
  618. END
  619. UNTIL block # NIL;
  620. blkSize := block.size + AddrSize;
  621. blkAdr := S.VAL( ADDRESS, block );
  622. DEC( heapAvailable, blkSize );
  623. IF blkSize > size THEN Recycle( blkAdr + size, blkSize - size ) END;
  624. INC( thruput, size );
  625. IF Stats THEN INC(Nnew); INC(NnewBytes, size) END;
  626. Machine.Fill32( blkAdr, size, 0 );
  627. IF saveSP # NIL THEN saveSP END;
  628. RETURN blkAdr
  629. END GetBlock;
  630. (** Private compiler interface. Do not use. *)
  631. PROCEDURE NewRec*( VAR p: ANY; tag: ADDRESS; isRealtime: BOOLEAN ); (* implementation of NEW( ptr ) *)
  632. VAR size, recSize: SIZE; ptr: ADDRESS; typeInfoAdr: ADDRESS; flags: SET;
  633. BEGIN
  634. S.GET( tag - AddrSize, typeInfoAdr );
  635. S.GET( typeInfoAdr + FlagsOfs, flags );
  636. IF ProtTypeBit IN flags THEN (* protected record *)
  637. NewProtRec( p, tag, isRealtime ); RETURN
  638. END;
  639. S.GET( tag, recSize );
  640. size := recSize + AddrSize; INC( size, (-size) MOD BlockSize );
  641. Machine.Acquire( Machine.Heaps );
  642. ptr := GetBlock( size ) + AddrSize;
  643. S.PUT( ptr - AddrSize, tag );
  644. p := S.VAL( ANY, ptr );
  645. Machine.Release( Machine.Heaps )
  646. END NewRec;
  647. (** Private compiler interface. Do not use. *)
  648. PROCEDURE NewProtRec*( VAR p: ANY; tag: ADDRESS; isRealtime: BOOLEAN );
  649. VAR recSize, size: SIZE; ptr0, ptr: ADDRESS;
  650. BEGIN
  651. S.GET( tag, recSize );
  652. (* add space for tag and header and round up to BlockSize *)
  653. size := recSize + ProtOfs + AddrSize; INC( size, (-size) MOD BlockSize );
  654. Machine.Acquire( Machine.Heaps );
  655. ptr0 := GetBlock( size ) + AddrSize;
  656. S.PUT( ptr0 - AddrSize, ptr0 ); (* set the tag needed by Sweep *)
  657. S.PUT( ptr0, size - AddrSize ); (* size, needed by procedure SizeOf(blk) *)
  658. ptr := ptr0 + ProtOfs; (* mod 32 = 16 ! *)
  659. S.PUT( ptr + HeapBlockOffset, ptr0 );
  660. S.PUT( ptr + TypeDescOffset, tag ); (* set the tag *)
  661. p := S.VAL( ANY, ptr );
  662. Machine.Release( Machine.Heaps );
  663. END NewProtRec;
  664. PROCEDURE SetPC*( p: ANY );
  665. BEGIN
  666. (* not implemented *)
  667. HALT( 100 );
  668. END SetPC;
  669. (** Private compiler interface. Do not use. *)
  670. PROCEDURE NewSys*( VAR p: ANY; size: SIZE; isRealtime: BOOLEAN ); (* implementation of S.NEW(ptr, size) *)
  671. VAR ptr: ADDRESS;
  672. BEGIN
  673. size := size + AddrSize + SysOfs; INC( size, (-size) MOD BlockSize );
  674. Machine.Acquire( Machine.Heaps );
  675. ptr := GetBlock( size ) + AddrSize;
  676. S.PUT( ptr - AddrSize, ptr ); (* tag needed by Sweep *)
  677. S.PUT( ptr, size - AddrSize ); (* size, needed by procedure SizeOf(blk) *)
  678. S.PUT( ptr + AddrSize, S.VAL( ADDRESS, -AddrSize ) );
  679. S.PUT( ptr + SysOfs - AddrSize, ptr ); (* tag *)
  680. p := S.VAL( ANY, ptr + SysOfs ); (* mod 16 = 8 ! *)
  681. Machine.Release( Machine.Heaps )
  682. END NewSys;
  683. (** Private compiler interface. Do not use. *)
  684. PROCEDURE NewArr*( VAR p: ANY; eltag: ADDRESS; nofelem, nofdim: SIZE; isRealtime: BOOLEAN );
  685. VAR
  686. sTB: StaticTypeBlock;
  687. arrSize, blkSize, dataOffset: SIZE; ptr, firstElem: ADDRESS;
  688. BEGIN
  689. sTB := S.VAL( StaticTypeBlock, eltag );
  690. arrSize := nofelem*sTB.recSize;
  691. IF arrSize = 0 THEN
  692. NewSys( p, nofdim*4 + 3*AddrSize, isRealtime );
  693. ELSE
  694. dataOffset := 3*AddrSize + nofdim*AddrSize;
  695. INC( dataOffset, (-dataOffset) MOD ArrayAlignment );
  696. IF LEN( sTB.pointerOffsets^ ) = 0 THEN
  697. (* no pointers in element type *)
  698. NewSys( p, dataOffset + arrSize, isRealtime );
  699. ELSE
  700. blkSize := dataOffset + arrSize + AddrSize; INC( blkSize, (-blkSize) MOD BlockSize );
  701. Machine.Acquire( Machine.Heaps );
  702. ptr := GetBlock( blkSize ) + AddrSize;
  703. S.PUT( ptr - AddrSize, eltag + 2 (*ArrayBit*) );
  704. firstElem := ptr + dataOffset;
  705. S.PUT( ptr, firstElem + arrSize - sTB.recSize ); (* last elem *)
  706. (* ptr + 4 is reserved for mark phase *)
  707. S.PUT( ptr + 2*AddrSize, firstElem );
  708. p := S.VAL( ANY, ptr );
  709. Machine.Release( Machine.Heaps )
  710. END
  711. END;
  712. END NewArr;
  713. TYPE
  714. ArrayDataBlockDesc*= RECORD
  715. numElems: SIZE;
  716. current: ADDRESS; (* unused *)
  717. first: ADDRESS;
  718. END;
  719. UnsafeArray= POINTER {UNSAFE} TO UnsafeArrayDesc;
  720. UnsafeArrayDesc = RECORD (ArrayDataBlockDesc)
  721. len: ARRAY 8 OF SIZE;
  722. END;
  723. (* replacement for overcomplicated code emission -- at the cost of a slightly increased runtime cost *)
  724. PROCEDURE NewArray*(CONST a: ARRAY OF SIZE; tag: ADDRESS; staticElements, elementSize: SIZE; VAR dest: ANY);
  725. VAR p: ANY; dim: SIZE;
  726. PROCEDURE GetSize(): SIZE;
  727. VAR i: SIZE; size: SIZE;
  728. BEGIN
  729. size := 1;
  730. FOR i := 0 TO dim-1 DO
  731. size := size * a[i];
  732. END;
  733. RETURN size*staticElements;
  734. END GetSize;
  735. PROCEDURE SetSizes(dest {UNTRACED}: UnsafeArray);
  736. VAR i: SIZE;
  737. BEGIN
  738. FOR i := 0 TO dim-1 DO
  739. dest.len[i] := a[dim-1-i];
  740. END;
  741. END SetSizes;
  742. BEGIN
  743. (* static elements is requred for this case : POINTER TO ARRAY OF ARRAY X OF RecordWithPointer *)
  744. dim := LEN( a,0 );
  745. IF tag = NIL THEN
  746. NewSys(p, GetSize() * elementSize + dim * SIZEOF(ADDRESS) + 3 *SIZEOF(ADDRESS) + (dim DIV 2) * 2 * SIZEOF(ADDRESS), FALSE);
  747. ELSE
  748. NewArr(p, tag, GetSize(), dim, FALSE);
  749. END;
  750. SetSizes(p);
  751. dest := p;
  752. END NewArray;
  753. PROCEDURE FillStaticType* ( VAR staticTypeAddr: ADDRESS;
  754. startAddr, typeInfoAdr: ADDRESS;
  755. size, recSize: SIZE;
  756. numPtrs, numSlots: LONGINT );
  757. VAR
  758. p, offset: ADDRESS; sTB {UNTRACED}: StaticTypeBlock;
  759. BEGIN
  760. Machine.Acquire( Machine.Heaps );
  761. Machine.Fill32( startAddr, size, 0 ); (* clear whole static type, size MOD AddrSize = 0 implicitly, see WriteType in PCOF.Mod *)
  762. S.PUT( startAddr, S.VAL( ADDRESS, -AddrSize ) ); (* sentinel *)
  763. (* methods and tags filled in later *)
  764. offset := AddrSize*(numSlots + 1 + 1); (* #methods, max. no. of tags, method end marker (sentinel), pointer to type information*)
  765. p := startAddr + offset;
  766. S.PUT( p - AddrSize, typeInfoAdr ); (* pointer to typeInfo *)
  767. sTB := S.VAL( StaticTypeBlock, p );
  768. sTB.recSize := recSize;
  769. staticTypeAddr := p;
  770. (* create the pointer for the dynamic array of pointer offsets, the dynamic array of pointer offsets
  771. is stored in the static type descriptor, it has no header part *)
  772. INC( p, SIZEOF(StaticTypeDesc) );
  773. IF p MOD (2 * AddrSize) # 0 THEN INC( p, AddrSize ) END;
  774. S.PUT( p + 3 * AddrSize, numPtrs ); (* internal structure of dynamic array without pointers: the first 3 fields are unused *)
  775. sTB.pointerOffsets := S.VAL( PointerOffsets, p ); (* the fourth field contains the dimension of the array *)
  776. (* ptrOfs filled in later *)
  777. Machine.Release( Machine.Heaps )
  778. END FillStaticType;
  779. (*------------------------------ misc ----------------------------------------*)
  780. (** WriteType - Write a type name (for tracing only). *)
  781. PROCEDURE WriteType*( t: ADDRESS ); (* t is static type descriptor *)
  782. VAR m, a: ADDRESS; i: LONGINT; ch: CHAR;
  783. BEGIN
  784. S.GET( t - AddrSize, t );
  785. S.GET( t + 4*AddrSize, m );
  786. IF m # 0 THEN
  787. a := m + AddrSize;
  788. i := 0; S.GET( a, ch );
  789. WHILE (ch >= '0') & (ch <= 'z') & (i < 32) DO
  790. Trace.Char( ch );
  791. INC( i ); S.GET( a + i, ch )
  792. END
  793. ELSE Trace.String( "NIL" )
  794. END;
  795. Trace.Char( '.' );
  796. a := t + 5*AddrSize; i := 0; S.GET( a, ch );
  797. WHILE (ch >= '0') & (ch <= 'z') & (i < 32) DO
  798. Trace.Char( ch );
  799. INC( i ); S.GET( a + i, ch )
  800. END;
  801. IF i = 0 THEN Trace.String( "-" ) END;
  802. END WriteType;
  803. PROCEDURE ValidAddress*( p: ADDRESS ): BOOLEAN;
  804. VAR sb: Machine.MemoryBlock;
  805. BEGIN
  806. IF (p # 0 ) & (p MOD 4 = 0) THEN
  807. sb := Machine.memBlockHead;
  808. WHILE sb # NIL DO
  809. IF (sb.beginBlockAdr <= p) & (p <= sb.endBlockAdr) THEN RETURN TRUE END;
  810. sb := sb.next;
  811. END
  812. END;
  813. RETURN FALSE
  814. END ValidAddress;
  815. PROCEDURE ValidPointer( p: ADDRESS ): BOOLEAN; (* check if p is a valid pointer into the Heap *)
  816. VAR tag: ADDRESS; ok: BOOLEAN;
  817. BEGIN
  818. ok := FALSE; tag := 0;
  819. IF (p MOD 8 = 0) & ValidAddress( p ) THEN
  820. IF p MOD 16 = 8 THEN ok := TRUE (* subobject or sysblock *)
  821. ELSE
  822. S.GET( p - AddrSize, tag );
  823. ok := ValidAddress( tag DIV 4 * 4 )
  824. END
  825. END;
  826. IF ~ok THEN
  827. Trace.String( "illegal pointer value: " ); Trace.Hex( p, -8 );
  828. IF tag # 0 THEN
  829. Trace.String( " (bad tag: " ); Trace.Hex( tag, -8 ); Trace.Char( ')' )
  830. END;
  831. Trace.Ln
  832. END;
  833. RETURN ok
  834. END ValidPointer;
  835. (* Returns the size in bytes of the remaining free heap *)
  836. PROCEDURE Available( ): SIZE;
  837. VAR i: LONGINT; avail: SIZE; block: FreeBlock;
  838. BEGIN
  839. avail := 0; i := 0;
  840. WHILE i <= MaxFreeLists DO
  841. block := freeLists[i].first;
  842. WHILE block # NIL DO
  843. INC( avail, block.size + AddrSize ); block := block.next
  844. END;
  845. INC( i )
  846. END;
  847. RETURN avail
  848. END Available;
  849. (** Returns the total heap size of the Oberon system. *)
  850. PROCEDURE HeapSize*( ): SIZE;
  851. BEGIN
  852. RETURN heapSize;
  853. END HeapSize;
  854. (** none portable, only for debugging *)
  855. PROCEDURE InspectFreeLists*;
  856. BEGIN
  857. Machine.Acquire( Machine.Heaps );
  858. ShowFreeLists( "" );
  859. Machine.Release( Machine.Heaps );
  860. END InspectFreeLists;
  861. PROCEDURE GetHeapInfo*( VAR total, free, largest: SIZE );
  862. VAR i: LONGINT; block: FreeBlock;
  863. BEGIN
  864. free := 0; largest := 0; i := 0;
  865. Machine.Acquire( Machine.Heaps );
  866. total := heapSize;
  867. WHILE i <= MaxFreeLists DO
  868. block := freeLists[i].first;
  869. WHILE block # NIL DO
  870. INC( free, block.size + AddrSize );
  871. IF block.size > largest THEN largest := block.size END;
  872. block := block.next;
  873. END;
  874. INC( i )
  875. END;
  876. Machine.Release( Machine.Heaps );
  877. END GetHeapInfo;
  878. PROCEDURE Used*( ): SIZE;
  879. VAR used: SIZE;
  880. BEGIN
  881. Machine.Acquire( Machine.Heaps );
  882. used := heapSize - heapAvailable;
  883. Machine.Release( Machine.Heaps );
  884. RETURN used
  885. END Used;
  886. PROCEDURE DetermineHeapSize( ): SIZE;
  887. VAR heap: SIZE; sb: Machine.MemoryBlock;
  888. BEGIN
  889. sb := Machine.memBlockHead; heap := 0;
  890. WHILE sb # NIL DO heap := heap + sb.size; sb := sb.next END;
  891. RETURN heap;
  892. END DetermineHeapSize;
  893. (*------------------ Initialization --------------------------------------------------*)
  894. (*
  895. (* for debugging the static linker output *)
  896. PROCEDURE BlockInfo( block: ADDRESS );
  897. VAR
  898. lastElem: ADDRESS; recSize, blockSize: SIZE;
  899. tag0, ttag, tag: ADDRESS;
  900. BEGIN
  901. S.GET( block, tag );
  902. tag0 := tag DIV 4 * 4 );
  903. S.GET( tag0, recSize );
  904. Trace.Hex( block, -8 ); Trace.Char( ' ' ); Trace.Hex( tag0, -8 ); Trace.Char( ' ' );
  905. IF ODD( tag DIV 2 ) THEN
  906. S.GET( block + AddrSize, lastElem );
  907. blockSize := lastElem + recSize - block;
  908. INC( blockSize, (-blockSize) MOD BlockSize );
  909. Trace.String( "array of " ); WriteType( tag0 )
  910. ELSE
  911. blockSize := recSize + AddrSize;
  912. INC( blockSize, (-blockSize) MOD BlockSize );
  913. IF tag0 # block + AddrSize THEN
  914. WriteType( tag0 )
  915. ELSE
  916. S.GET( block + SysOfs, ttag );
  917. IF ttag = tag0 THEN Trace.String( "sysblock" )
  918. ELSE
  919. S.GET( block + ProtOfs - AddrSize, ttag );
  920. IF ttag = tag0 THEN
  921. Trace.String( "prot. " );
  922. S.GET( block + ProtOfs, ttag ); WriteType( ttag )
  923. ELSE
  924. Trace.String( "?" )
  925. END
  926. END
  927. END
  928. END;
  929. Trace.Char( ' ' ); Trace.Int( blockSize, 1 );
  930. Trace.Ln
  931. END BlockInfo;
  932. *)
  933. PROCEDURE InitHeap;
  934. VAR adr2: ADDRESS;
  935. block, tag: ADDRESS; frBlock:FreeBlock;
  936. n: LONGINT;
  937. str: ARRAY 32 OF CHAR;
  938. BEGIN
  939. GC := EmptyProc; (* no GC until EmptyProc gets replaced (in module Objects) *)
  940. nofcand := 0;
  941. block := Machine.memBlockHead.beginBlockAdr;
  942. S.GET( block, tag ); n := 0;
  943. WHILE tag # 0 DO
  944. (* IF n < 200 THEN BlockInfo( block ); INC( n ) END; *)
  945. INC( block, SizeOf( block ) );
  946. S.GET( block, tag );
  947. END;
  948. S.PUT( block, block + AddrSize ); (* tag *)
  949. S.PUT( block + AddrSize, Machine.memBlockHead.endBlockAdr - block - AddrSize ); (* size *)
  950. S.PUT( block + AddrSize + SizeSize, S.VAL( ADDRESS, 0 ) ); (* next *)
  951. ClearFreeLists;
  952. freeLists[MaxFreeLists].first := S.VAL( FreeBlock, block );
  953. Machine.ExpandHeap( 0, 3*Machine.MemBlockSize - 2*BlockSize, S.VAL( ADDRESS, frBlock ), adr2 );
  954. IF frBlock # NIL THEN freeLists[MaxFreeLists].first.next := frBlock END;
  955. heapSize := DetermineHeapSize();
  956. heapAvailable := Available();
  957. Machine.GetConfig( "DisableShrinkHeap", str );
  958. shrinkDisabled := str[0] = '1';
  959. IF shrinkDisabled THEN
  960. Trace.StringLn( "#### Heap shrinking disabled" );
  961. END;
  962. IF Stats THEN
  963. Ngc := 0;
  964. Nmark := 0; Nmarked := 0; NfinalizeAlive := 0; NfinalizeDead := 0;
  965. NgcCyclesMark := 0; NgcCyclesLastRun := 0; NgcCyclesMax := 0; NgcCyclesAllRuns := 0;
  966. END
  967. END InitHeap
  968. BEGIN
  969. InitHeap;
  970. END Heaps.