compacting-gc.red 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. %
  2. % GC.RED - Compacting garbage collector for PSL
  3. %
  4. % Author: Martin Griss and Eric Benson
  5. % Symbolic Computation Group
  6. % Computer Science Dept.
  7. % University of Utah
  8. % Date: 28 August 1981
  9. % Copyright (c) 1981 University of Utah
  10. %
  11. % All data types have either explicit header tag in first item,
  12. % or are assumed to be 1st element of pair.
  13. % Revision History:
  14. % Edit by Cris Perdue, 16 Feb 1983 1407-PST
  15. % Fixed GtHeap and collector(s) to use only HeapLast, not HeapPreviousLast
  16. % Sets HeapTrapped to NIL now.
  17. % Using known-free-space function
  18. % Added check of Heap-Warn-Level after %Reclaim
  19. % Defined and used known-free-space function
  20. % <PSL.KERNEL>COMPACTING-GC.RED.9, 4-Oct-82 17:59:55, Edit by BENSON
  21. % Added GCTime!*
  22. % <PSL.KERNEL>COMPACTING-GC.RED.3, 21-Sep-82 10:43:21, Edit by BENSON
  23. % Flagged most functions internal
  24. % (M.L. Griss, March, 1977).
  25. % (Update to speed up, July 1978)
  26. % Converted to Syslisp July 1980
  27. % En-STRUCT-ed, Eric Benson April 1981
  28. % Added EVECT tag, M. Griss, 3 July 1982
  29. fluid '(!*GC % Controls printing of statistics
  30. GCTime!* % Total amount of time spent in GC
  31. GCKnt!* % count of # of GC's since system build
  32. heap!-warn!-level); % Continuable error if this much not
  33. % free after %Reclaim.
  34. LoadTime <<
  35. !*GC := T; % Do print GC messages (SL Rep says no)
  36. GCTime!* := 0;
  37. GCKnt!* := 0; % Initialize to zero
  38. Heap!-Warn!-Level := 1000;
  39. >>;
  40. on Syslisp;
  41. % Predicates for whether to follow pointers
  42. external WVar HeapLowerBound, % Bottom of heap
  43. HeapUpperBound, % Top of heap
  44. HeapLast, % Last item allocated
  45. HeapTrapped; % Boolean: has trap occurred since GC?
  46. CompileTime <<
  47. flag('(MarkFromAllBases BuildRelocationFields UpdateAllBases CompactHeap
  48. MarkFromOneSymbol MakeIDFreeList
  49. GCMessage MarkFromSymbols MarkFromRange MarkFromBase MarkFromVector
  50. GCError UpdateSymbols UpdateRegion UpdateItem UpdateHeap),
  51. 'InternalFunction);
  52. syslsp smacro procedure PointerTagP X;
  53. X > PosInt and X < Code;
  54. syslsp smacro procedure WithinHeapPointer X;
  55. X >= HeapLowerBound and X <= HeapLast;
  56. >>;
  57. % Marking primitives
  58. internal WConst GCMarkValue = 8#777,
  59. HSkip = Forward;
  60. CompileTime <<
  61. syslsp smacro procedure Mark X; % Get GC mark bits in item X points to
  62. GCField @X;
  63. syslsp smacro procedure SetMark X; % Set GC mark bits in item X points to
  64. GCField @X := GCMarkValue;
  65. syslsp smacro procedure ClearMark X; % Clear GC mark bits in item X points to
  66. GCField @X := if NegIntP @X then -1 else 0;
  67. syslsp smacro procedure Marked X; % Is item pointed to by X marked?
  68. Mark X eq GCMarkValue;
  69. syslsp smacro procedure MarkID X;
  70. Field(SymNam X, TagStartingBit, TagBitLength) := Forward;
  71. syslsp smacro procedure MarkedID X;
  72. Tag SymNam X eq Forward;
  73. syslsp smacro procedure ClearIDMark X;
  74. Field(SymNam X, TagStartingBit, TagBitLength) := STR;
  75. % Relocation primitives
  76. syslsp smacro procedure SkipLength X; % Stored in heap header
  77. Inf @X;
  78. syslsp smacro procedure PutSkipLength(X, L); % Store in heap header
  79. Inf @X := L;
  80. put('SkipLength, 'Assign!-Op, 'PutSkipLength);
  81. >>;
  82. internal WConst BitsInSegment = 13,
  83. SegmentLength = LShift(1, BitsInSegment),
  84. SegmentMask = SegmentLength - 1;
  85. internal WConst GCArraySize = LShift(HeapSize, -BitsInSegment) + 1;
  86. internal WArray GCArray[GCArraySize];
  87. CompileTime <<
  88. syslsp smacro procedure SegmentNumber X; % Get segment part of pointer
  89. LShift(X - HeapLowerBound, -BitsInSegment);
  90. syslsp smacro procedure OffsetInSegment X; % Get offset part of pointer
  91. LAnd(X - HeapLowerBound, SegmentMask);
  92. syslsp smacro procedure MovementWithinSegment X; % Reloc field in item
  93. GCField @X;
  94. syslsp smacro procedure PutMovementWithinSegment(X, M); % Store reloc field
  95. GCField @X := M;
  96. syslsp smacro procedure ClearMovementWithinSegment X; % Clear reloc field
  97. GCField @X := if NegIntP @X then -1 else 0;
  98. put('MovementWithinSegment, 'Assign!-Op, 'PutMovementWithinSegment);
  99. syslsp smacro procedure SegmentMovement X; % Segment table
  100. GCArray[X];
  101. syslsp smacro procedure PutSegmentMovement(X, M); % Store in seg table
  102. GCArray[X] := M;
  103. put('SegmentMovement, 'Assign!-Op, 'PutSegmentMovement);
  104. syslsp smacro procedure Reloc X; % Compute pointer adjustment
  105. X - (SegmentMovement SegmentNumber X + MovementWithinSegment X);
  106. >>;
  107. external WVar ST, % stack pointer
  108. StackLowerBound; % bottom of stack
  109. % Base registers marked from by collector
  110. % SymNam, SymPrp and SymVal are declared for all
  111. external WVar NextSymbol; % next ID number to be allocated
  112. external WVar BndStkLowerBound, % Bottom of binding stack
  113. BndStkPtr; % Binding stack pointer
  114. internal WVar StackEnd, % Holds address of bottom of stack
  115. StackStart, % Holds address of top of stack
  116. MarkTag, % Used by MarkFromBase only
  117. Hole, % First location moved in heap
  118. HeapShrink, % Total amount reclaimed
  119. StartingRealTime;
  120. syslsp procedure Reclaim(); %. User call to garbage collector
  121. << !%Reclaim();
  122. NIL >>;
  123. syslsp procedure !%Reclaim(); % Garbage collector
  124. << StackEnd := MakeAddressFromStackPointer ST - FrameSize();
  125. StackStart := StackLowerBound;
  126. if LispVar !*GC then ErrorPrintF "*** Garbage collection starting";
  127. StartingRealTime := TimC();
  128. LispVar GCKnt!* := LispVar GCKnt!* + 1; % must be INUM > 0, so needn't chk
  129. MarkFromAllBases();
  130. MakeIDFreeList();
  131. BuildRelocationFields();
  132. UpdateAllBases();
  133. CompactHeap();
  134. HeapLast := HeapLast - HeapShrink;
  135. StartingRealTime := TimC() - StartingRealTime;
  136. LispVar GCTime!* := Plus2(LispVar GCTime!*, StartingRealTime);
  137. if LispVar !*GC then GCMessage();
  138. HeapTrapped := NIL;
  139. if IntInf known!-free!-space() < IntInf (LispVar Heap!-Warn!-Level) then
  140. ContinuableError(99, "Heap space low", NIL);
  141. >>;
  142. syslsp procedure MarkFromAllBases();
  143. begin scalar B;
  144. MarkFromSymbols();
  145. MarkFromRange(StackStart, StackEnd);
  146. B := BndStkLowerBound;
  147. while << B := AdjustBndStkPtr(B, 1);
  148. B <= BndStkPtr >> do
  149. MarkFromBase @B;
  150. end;
  151. syslsp procedure MarkFromSymbols();
  152. begin scalar B;
  153. MarkFromOneSymbol 128; % mark NIL first
  154. for I := 0 step 1 until 127 do
  155. if not MarkedID I then MarkFromOneSymbol I;
  156. for I := 0 step 1 until MaxObArray do
  157. << B := ObArray I;
  158. if B > 0 and not MarkedID B then MarkFromOneSymbol B >>;
  159. end;
  160. syslsp procedure MarkFromOneSymbol X;
  161. % SymNam has to be marked from before marking ID, since the mark uses its tag
  162. % No problem since it's only a string, can't reference itself.
  163. << MarkFromBase SymNam X;
  164. MarkID X;
  165. MarkFromBase SymPrp X;
  166. MarkFromBase SymVal X >>;
  167. syslsp procedure MarkFromRange(Low, High);
  168. for Ptr := Low step 1 until High do MarkFromBase @Ptr;
  169. syslsp procedure MarkFromBase Base;
  170. begin scalar MarkInfo;
  171. MarkTag := Tag Base;
  172. if not PointerTagP MarkTag then return
  173. << if MarkTag = ID and not null Base then
  174. << MarkInfo := IDInf Base;
  175. if not MarkedID MarkInfo then MarkFromOneSymbol MarkInfo >> >>;
  176. MarkInfo := Inf Base;
  177. if not WithinHeapPointer MarkInfo
  178. or Marked MarkInfo then return;
  179. SetMark MarkInfo;
  180. CommentOutCode CheckAndSetMark MarkInfo;
  181. return if MarkTag eq VECT or MarkTag eq EVECT then
  182. MarkFromVector MarkInfo
  183. else if MarkTag eq PAIR then
  184. << MarkFromBase car Base;
  185. MarkFromBase cdr Base >>;
  186. end;
  187. CommentOutCode <<
  188. syslsp procedure CheckAndSetMark P;
  189. begin scalar HeadAtP;
  190. HeadAtP := Tag @P;
  191. case MarkTag of
  192. STR:
  193. if HeadAtP eq HBYTES then SetMark P;
  194. FIXN, FLTN, BIGN, WRDS:
  195. if HeadAtP eq HWRDS then SetMark P;
  196. VECT, EVECT:
  197. if HeadAtP eq HVECT then SetMark P;
  198. PAIR:
  199. SetMark P;
  200. default:
  201. GCError("Internal error in marking phase, at %o", P)
  202. end;
  203. end;
  204. >>;
  205. syslsp procedure MarkFromVector Info;
  206. begin scalar Uplim;
  207. CommentOutCode if Tag @Info neq HVECT then return;
  208. Uplim := &VecItm(Info, VecLen Info);
  209. for Ptr := &VecItm(Info, 0) step 1 until Uplim do
  210. MarkFromBase @Ptr;
  211. end;
  212. syslsp procedure MakeIDFreeList();
  213. begin scalar Previous;
  214. for I := 0 step 1 until 128 do
  215. ClearIDMark I;
  216. Previous := 129;
  217. while MarkedID Previous and Previous <= MaxSymbols do
  218. << ClearIDMark Previous;
  219. Previous := Previous + 1 >>;
  220. if Previous >= MaxSymbols then
  221. NextSymbol := 0
  222. else
  223. NextSymbol := Previous; % free list starts here
  224. for I := Previous + 1 step 1 until MaxSymbols do
  225. if MarkedID I then ClearIDMark I
  226. else
  227. << SymNam Previous := I;
  228. Previous := I >>;
  229. SymNam Previous := 0; % end of free list
  230. end;
  231. syslsp procedure BuildRelocationFields();
  232. %
  233. % Pass 2 - Turn off GC marks and Build SEGKNTs
  234. %
  235. begin scalar CurrentItem, SGCurrent, IGCurrent, TmpIG, DCount, SegLen;
  236. SGCurrent := IGCurrent := 0;
  237. SegmentMovement SGCurrent := 0; % Dummy
  238. Hole := HeapLowerBound - 1; % will be first hole
  239. DCount := HeapShrink := 0; % holes in current segment, total holes
  240. CurrentItem := HeapLowerBound;
  241. while CurrentItem < HeapLast do
  242. begin scalar Incr;
  243. SegLen := case Tag @CurrentItem of
  244. BTRTAG, CODE, NEGINT, POSINT, ID, UNBOUND,
  245. STR, BYTES, FIXN, FLTN, BIGN, WRDS, Halfwords, PAIR, VECT, EVECT:
  246. 2; % must be first of pair
  247. HBYTES:
  248. 1 + StrPack StrLen CurrentItem;
  249. HHalfwords:
  250. 1 + HalfWordPack StrLen CurrentItem;
  251. HWRDS:
  252. 1 + WrdPack WrdLen CurrentItem;
  253. HVECT:
  254. 1 + VectPack VecLen CurrentItem;
  255. HSKIP:
  256. SkipLength CurrentItem;
  257. default:
  258. GCError("Illegal item in heap at %o", CurrentItem)
  259. end; % case
  260. if Marked CurrentItem then % a hole
  261. if HeapShrink = 0 then
  262. ClearMark CurrentItem
  263. else % segment also clears mark
  264. << MovementWithinSegment CurrentItem := DCount; % incremental shift
  265. Incr := 0 >> % no shift
  266. else
  267. << @CurrentItem := MkItem(HSKIP, SegLen); % a skip mark
  268. Incr := 1; % more shift
  269. if Hole < HeapLowerBound then Hole := CurrentItem >>;
  270. TmpIG := IGCurrent + SegLen; % set SEG size
  271. CurrentItem := CurrentItem + SegLen;
  272. while TmpIG >= SegmentLength do
  273. begin scalar Tmp;
  274. Tmp := SegmentLength - IGCurrent; % Expand to next SEGMENT
  275. SegLen := SegLen - Tmp;
  276. if Incr eq 1 then HeapShrink := HeapShrink + Tmp;
  277. DCount := IGCurrent := 0;
  278. SGCurrent := SGCurrent + 1;
  279. SegmentMovement SGCurrent := HeapShrink; % Store Next Base
  280. TmpIG := TmpIG - SegmentLength;
  281. end;
  282. IGCurrent := TmpIG;
  283. if Incr eq 1 then
  284. << HeapShrink := HeapShrink + SegLen;
  285. DCount := DCount + SegLen >>; % Add in Hole Size
  286. end;
  287. SegmentMovement(SGCurrent + 1) := HeapShrink;
  288. end;
  289. syslsp procedure UpdateAllBases();
  290. begin scalar B;
  291. UpdateSymbols();
  292. UpdateRegion(StackStart, StackEnd);
  293. B := BndStkLowerBound;
  294. while << B := AdjustBndStkPtr(B, 1);
  295. B <= BndStkPtr >> do
  296. UpdateItem B;
  297. UpdateHeap() >>;
  298. syslsp procedure UpdateSymbols();
  299. for I := 0 step 1 until MaxSymbols do
  300. begin scalar NameLoc;
  301. NameLoc := &SymNam I;
  302. if StringP @NameLoc then
  303. << UpdateItem NameLoc;
  304. UpdateItem &SymVal I;
  305. UpdateItem &SymPrp I >>;
  306. end;
  307. syslsp procedure UpdateRegion(Low, High);
  308. for Ptr := Low step 1 until High do UpdateItem Ptr;
  309. syslsp procedure UpdateHeap();
  310. begin scalar CurrentItem;
  311. CurrentItem := HeapLowerBound;
  312. while CurrentItem < HeapLast do
  313. begin
  314. case Tag @CurrentItem of
  315. BTRTAG, CODE, NEGINT, POSINT, ID, UNBOUND:
  316. CurrentItem := CurrentItem + 1;
  317. STR, BYTES, FIXN, FLTN, BIGN, WRDS, Halfwords, PAIR, VECT, EVECT:
  318. << if Inf @CurrentItem >= Hole and Inf @CurrentItem <= HeapLast then
  319. Inf @CurrentItem := Reloc Inf @CurrentItem;
  320. CurrentItem := CurrentItem + 1 >>;
  321. HBYTES:
  322. CurrentItem := CurrentItem + 1 + StrPack StrLen CurrentItem;
  323. HHalfwords:
  324. CurrentItem := CurrentItem + 1 + HalfwordPack StrLen CurrentItem;
  325. HWRDS:
  326. CurrentItem := CurrentItem + 1 + WrdPack WrdLen CurrentItem;
  327. HVECT:
  328. begin scalar Tmp;
  329. Tmp := VecLen CurrentItem;
  330. CurrentItem := CurrentItem + 1; % Move over header
  331. for I := 0 step 1 until Tmp do % VecLen + 1 items
  332. begin scalar Tmp2, Tmp3;
  333. Tmp2 := @CurrentItem;
  334. Tmp3 := Tag Tmp2;
  335. if PointerTagP Tmp3
  336. and Inf Tmp2 >= Hole and Inf Tmp2 <= HeapLast then
  337. Inf @CurrentItem := Reloc Inf Tmp2;
  338. CurrentItem := CurrentItem + 1;
  339. end;
  340. end;
  341. HSKIP:
  342. CurrentItem := CurrentItem + SkipLength CurrentItem;
  343. default:
  344. GCError("Internal error in updating phase at %o", CurrentItem)
  345. end; % case
  346. end
  347. end;
  348. syslsp procedure UpdateItem Ptr;
  349. begin scalar Tg, Info;
  350. Tg := Tag @Ptr;
  351. if not PointerTagP Tg then return;
  352. Info := INF @Ptr;
  353. if Info < Hole or Info > HeapLast then return;
  354. Inf @Ptr := Reloc Info;
  355. end;
  356. syslsp procedure CompactHeap();
  357. begin scalar OldItemPtr, NewItemPtr, SegLen;
  358. if Hole < HeapLowerBound then return;
  359. NewItemPtr := OldItemPtr := Hole;
  360. while OldItemPtr < HeapLast do
  361. begin;
  362. case Tag @OldItemPtr of
  363. BTRTAG, CODE, NEGINT, POSINT, ID, UNBOUND,
  364. STR, BYTES, FIXN, FLTN, BIGN, WRDS, Halfwords, PAIR, VECT, EVECT:
  365. SegLen := PairPack OldItemPtr;
  366. HBYTES:
  367. SegLen := 1 + StrPack StrLen OldItemPtr;
  368. HHalfwords:
  369. SegLen := 1 + HalfWordPack HalfwordLen OldItemPtr;
  370. HWRDS:
  371. SegLen := 1 + WrdPack WrdLen OldItemPtr;
  372. HVECT:
  373. SegLen := 1 + VectPack VecLen OldItemPtr;
  374. HSKIP:
  375. << OldItemPtr := OldItemPtr + SkipLength OldItemPtr;
  376. goto WhileNext >>;
  377. default:
  378. GCError("Internal error in compaction at %o", OldItemPtr)
  379. end; % case
  380. ClearMovementWithinSegment OldItemPtr;
  381. for I := 1 step 1 until SegLen do
  382. << @NewItemPtr := @OldItemPtr;
  383. NewItemPtr := NewItemPtr + 1;
  384. OldItemPtr := OldItemPtr + 1 >>;
  385. WhileNext:
  386. end;
  387. end;
  388. syslsp procedure GCError(Message, P);
  389. << ErrorPrintF("***** Fatal error during garbage collection");
  390. ErrorPrintF(Message, P);
  391. while T do Quit; >>;
  392. syslsp procedure GCMessage();
  393. << ErrorPrintF("*** GC %w: time %d ms",
  394. LispVar GCKnt!*, StartingRealTime);
  395. ErrorPrintF("*** %d recovered, %d stable, %d active, %d free",
  396. HeapShrink, Hole - HeapLowerBound,
  397. HeapLast - Hole,
  398. intinf known!-free!-space() ) >>;
  399. off SysLisp;
  400. END;