gc.c 91 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806
  1. /* File gc.c Copyright (c) Codemist Ltd, 1990-95 */
  2. /*
  3. * Garbage collection.
  4. * Fourth major version - now using Foster-style
  5. * algorithm for relocating vector heap, and support for handling
  6. * BPS via segmented handles. Pointer-reversing mark phase to go with same.
  7. *
  8. * Furthermore there is (optionally) a copying 2-space garbage
  9. * collector as well as the mark/slide one. Now do you understand
  10. * why this file seems so very long?
  11. */
  12. /* Signature: 302ffcb4 07-Mar-2000 */
  13. #include <stdarg.h>
  14. #include <string.h>
  15. #include <ctype.h>
  16. #include <math.h>
  17. #include "machine.h"
  18. #include "tags.h"
  19. #include "cslerror.h"
  20. #include "externs.h"
  21. #include "arith.h"
  22. #include "entries.h"
  23. #include "sys.h"
  24. #include "stream.h"
  25. #ifdef SOCKETS
  26. #include "sockhdr.h"
  27. #endif
  28. #ifdef TIMEOUT
  29. #include "timeout.h"
  30. #endif
  31. /*
  32. * This function is provided so that if some C compiler generates bad
  33. * code and I can not see a better way of correcting things, and if the
  34. * bad code goes away when there are lots of function calls to cause the
  35. * compiler to unload its registers etc, then I can write things like
  36. * dummy_function_call("Ha Ha", reference_this_var, and_this);
  37. * without it having any big effect on the results I obtain. I will
  38. * generally want to guard any such un-natural calls by a test that identifies
  39. * the C compiler involved. Of course I must try not to use this as a way
  40. * of permitting system-sensitive code to creep into CSL...
  41. */
  42. void MS_CDECL dummy_function_call(char *why, ...)
  43. {
  44. return;
  45. }
  46. CSLbool gc_method; /* YES if copying, NO if sliding */
  47. int32 gc_number = 0;
  48. static int32 cons_cells, symbol_heads, strings, user_vectors,
  49. big_numbers, box_floats, bytestreams, other_mem,
  50. litvecs, getvecs;
  51. #define is_immed(x) (is_immed_or_cons(x) && !is_cons(x))
  52. #ifndef DEMO_MODE
  53. static void non_recursive_mark(Lisp_Object *top)
  54. {
  55. /*
  56. * This code is written about as neatly as I know how ... I want to think of
  57. * it in terms of three chunks - descending down into lists, regular
  58. * climbing back out, and the special case of climbing back out when I have
  59. * just processed a vector. I like to think of this as a finite state
  60. * machine with three major groups of states, and a bunch of subsidiary
  61. * states that deal with (e.g.) scanning along vectors.
  62. */
  63. Lisp_Object b = (Lisp_Object)top,
  64. p = *top,
  65. w,
  66. nil = C_nil;
  67. Header h, *q;
  68. int32 i;
  69. /*
  70. * When I get to descend I have b as an unmarked address that is either
  71. * equal to top, or is a back-pointer as set up below. p is a normal
  72. * (i.e. unmarked) Lisp pointer, representing a tree to be marked. Only
  73. * at the very top of a call can p be immediate data at descend, and in that
  74. * case no marking is needed.
  75. * NB that the initial back pointer will seem tagged as either a CONS or a
  76. * SYMBOL, but certainly as a pointer datatype.
  77. */
  78. descend:
  79. switch ((int)p & TAG_BITS)
  80. {
  81. /*
  82. * If I have a cons cell I need to check if it has been visited before or
  83. * if one or both components are immediate - and extend my backwards
  84. * chain one step.
  85. */
  86. case TAG_CONS:
  87. #ifdef COMMON
  88. if (p == nil) goto ascend;
  89. #endif
  90. w = qcar(p);
  91. if (is_immed(w))
  92. { if (is_marked_i(w)) goto ascend;
  93. /*
  94. * To test if this cons cell was marked I had to classify the item
  95. * in its car, and if this was immediate data it makes sense to go
  96. * right ahead and probe the cdr.
  97. */
  98. qcar(p) = flip_mark_bit_i(w);
  99. w = qcdr(p);
  100. /*
  101. * Since I am not allowing myself to descend onto immediate data
  102. * I check for it here, and if both car and cdr of p were immediate
  103. * I can ascend forthwith.
  104. */
  105. if (is_immed(w) || w == nil) goto ascend;
  106. /*
  107. * Here I fill in a back-pointer and descend into the cdr of a pair.
  108. */
  109. qcdr(p) = flip_mark_bit_p(b);
  110. b = p;
  111. p = w;
  112. goto descend;
  113. }
  114. else if (is_marked_p(w)) goto ascend;
  115. /*
  116. * Here I fill in a back-pointer and descend into the car of a pair.
  117. * [would it be worth taking a special case on w == nil here?]
  118. */
  119. qcar(p) = flip_mark_bit_p(b);
  120. b = p;
  121. p = w;
  122. goto descend;
  123. /*
  124. * case TAG_FIXNUM:
  125. * case TAG_ODDS:
  126. * case TAG_SFLOAT:
  127. */
  128. default:
  129. return; /* assert (b==(Lisp_Object)top) here. */
  130. case TAG_SYMBOL:
  131. #ifndef COMMON
  132. if (p == nil) goto ascend;
  133. #endif
  134. h = qheader(p);
  135. /*
  136. * When I have finished every item that has been visited must be marked,
  137. * with cons cells marked in their car fields and vectors etc in the header
  138. * word. Furthermore the header of all vectors (including symbols) must
  139. * have been replaced by the start of a back-pointer chain identifying the
  140. * words that started off pointing at the vector. The pointers in this
  141. * chain must be marked, word-aligned pointers.
  142. */
  143. if (!is_odds(h) || is_marked_h(h)) /* Visited before */
  144. { q = &qheader(p); /* where I should chain */
  145. p = h; /* the previous header */
  146. goto ascend_from_vector;
  147. }
  148. /*
  149. * Now this is the first visit to a symbol.
  150. */
  151. qheader(p) = h = flip_mark_bit_h(h);
  152. /*
  153. * When components of a symbol are immediate or nil I do nothing.
  154. * (the test for nil is because I expect it to be cheap and to catch
  155. * common cases)
  156. */
  157. w = qvalue(p);
  158. if (!is_immed(w) && w != nil)
  159. { qvalue(p) = flip_mark_bit_p(b);
  160. b = p;
  161. p = w;
  162. goto descend;
  163. }
  164. w = qenv(p);
  165. if (!is_immed(w) && w != nil)
  166. { qenv(p) = flip_mark_bit_p(b);
  167. b = p;
  168. p = w;
  169. goto descend;
  170. }
  171. w = qpname(p);
  172. if (!is_immed(w) && w != nil)
  173. { qpname(p) = flip_mark_bit_p(b);
  174. b = p;
  175. p = w;
  176. goto descend;
  177. }
  178. w = qplist(p);
  179. if (!is_immed(w) && w != nil)
  180. { qplist(p) = flip_mark_bit_p(b);
  181. b = p;
  182. p = w;
  183. goto descend;
  184. }
  185. w = qfastgets(p);
  186. if (!is_immed(w) && w != nil)
  187. { qfastgets(p) = flip_mark_bit_p(b);
  188. b = p;
  189. p = w;
  190. goto descend;
  191. }
  192. #ifdef COMMON
  193. w = qpackage(p);
  194. if (!is_immed(w) && w != nil)
  195. { qpackage(p) = flip_mark_bit_p(b);
  196. b = p;
  197. p = w;
  198. goto descend;
  199. }
  200. #endif
  201. /*
  202. * When all components of the vector are marked I climb up the
  203. * back-pointer chain.
  204. */
  205. q = &qheader(p);
  206. p = h;
  207. goto ascend_from_vector;
  208. case TAG_NUMBERS:
  209. h = numhdr(p);
  210. if (!is_odds(h) || is_marked_h(h)) /* marked already. */
  211. { q = &numhdr(p);
  212. p = h;
  213. goto ascend_from_vector;
  214. }
  215. /*
  216. * For CSL the only case here is that of big integers, which have just
  217. * binary data in them. For Common Lisp I also have to cope with
  218. * ratios and complex numbers.
  219. */
  220. if (is_bignum_header(h))
  221. { q = &numhdr(p);
  222. p = flip_mark_bit_h(h);
  223. goto ascend_from_vector;
  224. }
  225. #ifdef COMMON
  226. numhdr(p) = h = flip_mark_bit_h(h);
  227. w = real_part(p); /* Or numerator of a ratio! */
  228. if (!is_immed(w))
  229. { real_part(p) = flip_mark_bit_p(b);
  230. b = p;
  231. p = w;
  232. goto descend;
  233. }
  234. w = imag_part(p); /* Or denominator of a ratio! */
  235. if (!is_immed(w))
  236. { imag_part(p) = flip_mark_bit_p(b);
  237. b = p;
  238. p = w;
  239. goto descend;
  240. }
  241. /*
  242. * get here if both components of a ratio/complex are immediate (e.g fixnums)
  243. */
  244. q = &numhdr(p);
  245. p = h;
  246. goto ascend_from_vector;
  247. #else
  248. abort(); /* Bad numeric type in CSL mode. */
  249. #endif
  250. case TAG_BOXFLOAT:
  251. h = flthdr(p);
  252. if (!is_odds(h) || is_marked_h(h))
  253. { q = &flthdr(p);
  254. p = h;
  255. goto ascend_from_vector;
  256. }
  257. q = &flthdr(p);
  258. p = flip_mark_bit_h(h);
  259. goto ascend_from_vector;
  260. case TAG_VECTOR:
  261. h = vechdr(p);
  262. if (!is_odds(h) || is_marked_h(h))
  263. { q = &vechdr(p);
  264. p = h;
  265. goto ascend_from_vector;
  266. }
  267. if (vector_holds_binary(h))
  268. { q = &vechdr(p);
  269. p = flip_mark_bit_h(h);
  270. goto ascend_from_vector;
  271. }
  272. vechdr(p) = h = flip_mark_bit_h(h);
  273. i = (int32)doubleword_align_up(length_of_header(h));
  274. if (is_mixed_header(h))
  275. i = 16; /* Only use first few pointers */
  276. while (i >= 8)
  277. { i -= 4;
  278. q = (Header *)((char *)p - TAG_VECTOR + i);
  279. w = *q;
  280. if (is_immed(w) || w == nil) continue;
  281. /*
  282. * For vectors I have to use all available mark bits to keep track of
  283. * where I am...
  284. */
  285. if (i == 4)
  286. /*
  287. * When descending into the first (or only) word of a vector I heave the
  288. * back-pointer marked, and note that the header word just before it
  289. * will be marked (either as a header word or as a pointer)
  290. */
  291. { *q = flip_mark_bit_p(b);
  292. b = p;
  293. p = w;
  294. }
  295. else if ((i & 4) == 0)
  296. /*
  297. * When descending a pointer at an even (word) address I leave the
  298. * back-pointer unmarked.
  299. */
  300. { *q = b;
  301. b = (Lisp_Object)((char *)p + i);
  302. p = w;
  303. }
  304. else
  305. /*
  306. * Finally when I descend into a pointer at an odd (word) address other
  307. * than the special case of the first such, I leave an unmarked back-pointer
  308. * but mark the word before the one I am following. The effect of all this is
  309. * that when I get back to the vector I am able to discriminate between these
  310. * various cases...
  311. */
  312. { *q = b;
  313. b = (Lisp_Object)((char *)p + i - 4);
  314. p = w;
  315. w = *(Lisp_Object *)((char *)b - TAG_VECTOR);
  316. if (is_immed(w)) w = flip_mark_bit_i(w);
  317. else w = flip_mark_bit_p(w);
  318. *(Lisp_Object *)((char *)b - TAG_VECTOR) = w;
  319. }
  320. goto descend;
  321. }
  322. /*
  323. * I drop through to here if all items in the vector were in fact
  324. * immediate values (e.g. fixnums), and thus there was no need to
  325. * dig deeper.
  326. */
  327. q = &vechdr(p);
  328. p = h;
  329. goto ascend_from_vector;
  330. }
  331. /*
  332. * When I get to ascend b is a back-pointer, and p is an unmarked pointer
  333. * to be put back into the place I descended through.
  334. */
  335. ascend:
  336. if (b == (Lisp_Object)top) return;
  337. switch ((int)b & TAG_BITS)
  338. {
  339. default:
  340. abort();
  341. case TAG_CONS:
  342. w = qcdr(b);
  343. if (is_immed(w) || w == nil)
  344. { w = qcar(b);
  345. qcar(b) = flip_mark_bit_p(p);
  346. p = b;
  347. b = flip_mark_bit_p(w);
  348. goto ascend;
  349. }
  350. else if (is_marked_p(w))
  351. { qcdr(b) = p;
  352. p = b;
  353. b = flip_mark_bit_p(w);
  354. goto ascend;
  355. }
  356. else
  357. { qcdr(b) = qcar(b);
  358. qcar(b) = flip_mark_bit_p(p);
  359. p = w;
  360. goto descend;
  361. }
  362. case TAG_SYMBOL:
  363. #ifdef COMMON
  364. w = qpackage(b);
  365. if (!is_immed(w) && is_marked_p(w))
  366. { qpackage(b) = p;
  367. goto try_nothing;
  368. }
  369. #endif
  370. w = qfastgets(b);
  371. if (!is_immed(w) && is_marked_p(w))
  372. { qfastgets(b) = p;
  373. goto try_package;
  374. }
  375. w = qplist(b);
  376. if (!is_immed(w) && is_marked_p(w))
  377. { qplist(b) = p;
  378. goto try_fastgets;
  379. }
  380. w = qpname(b);
  381. if (!is_immed(w) && is_marked_p(w))
  382. { qpname(b) = p;
  383. goto try_plist;
  384. }
  385. w = qenv(b);
  386. if (!is_immed(w) && is_marked_p(w))
  387. { qenv(b) = p;
  388. goto try_pname;
  389. }
  390. w = qvalue(b);
  391. if (!is_immed(w) && is_marked_p(w))
  392. { qvalue(b) = p;
  393. goto try_env;
  394. }
  395. abort(); /* backpointer not found */
  396. try_env:
  397. p = qenv(b);
  398. if (!is_immed(p) && p != nil && !is_marked_p(p))
  399. { qenv(b) = w;
  400. goto descend;
  401. }
  402. try_pname:
  403. p = qpname(b);
  404. if (!is_immed(p) && p != nil && !is_marked_p(p))
  405. { qpname(b) = w;
  406. goto descend;
  407. }
  408. try_plist:
  409. p = qplist(b);
  410. if (!is_immed(p) && p != nil && !is_marked_p(p))
  411. { qplist(b) = w;
  412. goto descend;
  413. }
  414. try_fastgets:
  415. p = qfastgets(b);
  416. if (!is_immed(p) && p != nil && !is_marked_p(p))
  417. { qfastgets(b) = w;
  418. goto descend;
  419. }
  420. try_package:
  421. #ifdef COMMON
  422. p = qpackage(b);
  423. if (!is_immed(p) && p != nil && !is_marked_p(p))
  424. { qpackage(b) = w;
  425. goto descend;
  426. }
  427. try_nothing:
  428. #endif
  429. q = &qheader(b);
  430. p = *q;
  431. b = flip_mark_bit_p(w);
  432. goto ascend_from_vector;
  433. #ifdef COMMON
  434. case TAG_NUMBERS:
  435. /*
  436. * If I get back to a NUMBERS than it must have been a ratio or a complex.
  437. */
  438. w = imag_part(b);
  439. if (is_immed(w))
  440. { w = real_part(b);
  441. real_part(b) = p;
  442. q = &numhdr(b);
  443. p = *q;
  444. b = flip_mark_bit_p(w);
  445. goto ascend_from_vector;
  446. }
  447. else if (is_marked_p(w))
  448. { imag_part(b) = p;
  449. q = &numhdr(p);
  450. p = *q;
  451. b = flip_mark_bit_p(w);
  452. goto ascend_from_vector;
  453. }
  454. else
  455. { imag_part(b) = real_part(b);
  456. real_part(b) = p;
  457. p = w;
  458. goto descend;
  459. }
  460. #endif
  461. case TAG_VECTOR:
  462. /*
  463. * If I get back to a vector it must have been a vector of Lisp_Objects,
  464. * not a vector of binary data. My back-pointer points part-way into it.
  465. * I can tell where I am by inspecting the state of mark bits on both parts
  466. * of the doubleword so identified.
  467. */
  468. w = *(Lisp_Object *)((char *)b - TAG_VECTOR);
  469. if (is_immed(w) || is_marked_p(w))
  470. /*
  471. * Here I had been marking the pointer that was stored at an odd (word)
  472. * address.
  473. */
  474. { Lisp_Object w1 = *(Lisp_Object *)((char *)b - TAG_VECTOR + 4);
  475. *(Lisp_Object *)((char *)b - TAG_VECTOR + 4) = p;
  476. if (is_marked_p(w1)) /* End of this vector */
  477. { q = (Header *)((char *)b - TAG_VECTOR);
  478. p = w;
  479. b = flip_mark_bit_p(w1);
  480. goto ascend_from_vector;
  481. }
  482. p = w;
  483. w = w1;
  484. if (!is_immed(p))
  485. { p = flip_mark_bit_p(p);
  486. if (p != nil)
  487. { *(Lisp_Object *)((char *)b - TAG_VECTOR) = w1;
  488. goto descend;
  489. }
  490. }
  491. else p = flip_mark_bit_i(p);
  492. }
  493. *(Lisp_Object *)((char *)b - TAG_VECTOR) = p;
  494. /*
  495. * Now the doubleword I returned to has been marked (and tidied up),
  496. * so I need to scan back towards the header.
  497. */
  498. scan_vector_more:
  499. for (;;)
  500. { Lisp_Object w2;
  501. b = (Lisp_Object)((char *)b - 8);
  502. w2 = *(Lisp_Object *)((char *)b - TAG_VECTOR);
  503. p = *(Lisp_Object *)((char *)b - TAG_VECTOR + 4);
  504. if ((is_odds(w2) && is_header(w2)) ||
  505. (!is_immed(w2) && is_marked_p(w2)))
  506. /*
  507. * In this case I have reached the doubleword containing the header.
  508. */
  509. { if (!is_immed(p) && p != nil)
  510. { *(Lisp_Object *)((char *)b - TAG_VECTOR + 4) =
  511. flip_mark_bit_p(w);
  512. goto descend;
  513. }
  514. else
  515. { q = (Header *)((char *)b - TAG_VECTOR);
  516. p = w2;
  517. b = w;
  518. goto ascend_from_vector;
  519. }
  520. }
  521. /*
  522. * Otherwise I have another general doubleword to cope with.
  523. */
  524. if (!is_immed(p) && p != nil)
  525. { if (is_immed(w2)) w2 = flip_mark_bit_i(w2);
  526. else w2 = flip_mark_bit_p(w2);
  527. *(Lisp_Object *)((char *)b - TAG_VECTOR) = w2;
  528. *(Lisp_Object *)((char *)b - TAG_VECTOR + 4) = w;
  529. goto descend;
  530. }
  531. if (!is_immed(w2) && w2 != nil)
  532. { p = w2;
  533. *(Lisp_Object *)((char *)b - TAG_VECTOR) = w;
  534. goto descend;
  535. }
  536. continue; /* Step back another doubleword */
  537. }
  538. }
  539. ascend_from_vector:
  540. /*
  541. * Here the item just marked was a vector. I need to leave a reversed
  542. * chain of pointers through its header word. q points to that header,
  543. * and p contains what used to be in the word at q.
  544. */
  545. if (b == (Lisp_Object)top)
  546. { *q = flip_mark_bit_p(b);
  547. *top = p;
  548. return;
  549. }
  550. switch ((int)b & TAG_BITS)
  551. {
  552. default:
  553. abort();
  554. case TAG_CONS:
  555. w = qcdr(b);
  556. if (is_immed(w) || w == nil)
  557. { w = qcar(b);
  558. qcar(b) = p;
  559. *q = flip_mark_bit_p((Lisp_Object *)&qcar(b));
  560. p = b;
  561. b = flip_mark_bit_p(w);
  562. goto ascend;
  563. }
  564. else if (is_marked_p(w))
  565. { qcdr(b) = p;
  566. *q = flip_mark_bit_p((Lisp_Object *)&qcdr(b));
  567. p = b;
  568. b = flip_mark_bit_p(w);
  569. goto ascend;
  570. }
  571. else
  572. { qcdr(b) = qcar(b);
  573. qcar(b) = p;
  574. *q = flip_mark_bit_p((Lisp_Object *)&qcar(b));
  575. p = w;
  576. goto descend;
  577. }
  578. case TAG_SYMBOL:
  579. #ifdef COMMON
  580. w = qpackage(b);
  581. if (!is_immed(w) && is_marked_p(w))
  582. { qpackage(b) = p;
  583. *q = flip_mark_bit_p((Lisp_Object *)&qpackage(b));
  584. goto try_nothing;
  585. }
  586. #endif
  587. w = qfastgets(b);
  588. if (!is_immed(w) && is_marked_p(w))
  589. { qfastgets(b) = p;
  590. *q = flip_mark_bit_p((Lisp_Object *)&qfastgets(b));
  591. goto try_package;
  592. }
  593. w = qplist(b);
  594. if (!is_immed(w) && is_marked_p(w))
  595. { qplist(b) = p;
  596. *q = flip_mark_bit_p((Lisp_Object *)&qplist(b));
  597. goto try_fastgets;
  598. }
  599. w = qpname(b);
  600. if (!is_immed(w) && is_marked_p(w))
  601. { qpname(b) = p;
  602. *q = flip_mark_bit_p((Lisp_Object *)&qpname(b));
  603. goto try_plist;
  604. }
  605. w = qenv(b);
  606. if (!is_immed(w) && is_marked_p(w))
  607. { qenv(b) = p;
  608. *q = flip_mark_bit_p((Lisp_Object *)&qenv(b));
  609. goto try_pname;
  610. }
  611. w = qvalue(b);
  612. if (!is_immed(w) && is_marked_p(w))
  613. { qvalue(b) = p;
  614. *q = flip_mark_bit_p((Lisp_Object *)&qvalue(b));
  615. goto try_env;
  616. }
  617. abort();
  618. #ifdef COMMON
  619. case TAG_NUMBERS:
  620. /*
  621. * If I get back to a NUMBERS than it must have been a ratio or a complex.
  622. */
  623. w = imag_part(b);
  624. if (is_immed(w))
  625. { w = real_part(b);
  626. real_part(b) = p;
  627. *q = flip_mark_bit_p((Lisp_Object *)&real_part(b));
  628. q = &numhdr(b);
  629. p = *q;
  630. b = flip_mark_bit_p(w);
  631. goto ascend_from_vector;
  632. }
  633. else if (is_marked_p(w))
  634. { imag_part(b) = p;
  635. *q = flip_mark_bit_p((Lisp_Object *)&imag_part(b));
  636. q = &numhdr(p);
  637. p = *q;
  638. b = flip_mark_bit_p(w);
  639. goto ascend_from_vector;
  640. }
  641. else
  642. { imag_part(b) = real_part(b);
  643. real_part(b) = p;
  644. *q = flip_mark_bit_p((Lisp_Object *)&real_part(b));
  645. p = w;
  646. goto descend;
  647. }
  648. #endif
  649. case TAG_VECTOR:
  650. /*
  651. * If I get back to a vector it must have been a vector of Lisp_Objects,
  652. * not a vector of binary data. My back-pointer points part-way into it.
  653. * I can tell where I am by inspecting the state of mark bits on both parts
  654. * of the doubleword so identified.
  655. */
  656. w = *(Lisp_Object *)((char *)b - TAG_VECTOR);
  657. if (is_immed(w) || is_marked_p(w))
  658. /*
  659. * Here I had been marking the pointer that was stored at an odd (word)
  660. * address.
  661. */
  662. { Lisp_Object w1 = *(Lisp_Object *)((char *)b - TAG_VECTOR + 4);
  663. *(Lisp_Object *)((char *)b - TAG_VECTOR + 4) = p;
  664. *q = flip_mark_bit_p((Lisp_Object)((char *)b - TAG_VECTOR + 4));
  665. if (is_marked_p(w1)) /* End of this vector */
  666. { q = (Header *)((char *)b - TAG_VECTOR);
  667. p = *q; /* May not be same as w still! */
  668. b = flip_mark_bit_p(w1);
  669. goto ascend_from_vector;
  670. }
  671. p = w;
  672. w = w1;
  673. if (!is_immed(p))
  674. { p = flip_mark_bit_p(p);
  675. if (p != nil)
  676. { *(Lisp_Object *)((char *)b - TAG_VECTOR) = w1;
  677. goto descend;
  678. }
  679. }
  680. else p = flip_mark_bit_i(p);
  681. *(Lisp_Object *)((char *)b - TAG_VECTOR) = p;
  682. }
  683. else
  684. { *(Lisp_Object *)((char *)b - TAG_VECTOR) = p;
  685. *q = flip_mark_bit_p((Lisp_Object)((char *)b - TAG_VECTOR));
  686. }
  687. /*
  688. * Now the doubleword I returned to has been marked (and tidied up),
  689. * so I need to scan back towards the header.
  690. */
  691. goto scan_vector_more;
  692. }
  693. }
  694. static void mark(Lisp_Object *pp)
  695. {
  696. /*
  697. * This mark procedure works by using the regular Lisp stack to
  698. * store things while traversing the lists. A null pointer on the
  699. * stack marks the end of the section that is being used. If too
  700. * much stack is (about to be) used I switch over to the pointer-
  701. * reversing code given above, which is slower but which uses
  702. * bounded workspace. My measurements (on just one computer) show the
  703. * stack-based code only 25% faster than the pointer-reversing version,
  704. * which HARDLY seems enough to justify all this extra code, but then
  705. * fast garbage collection is very desirable and every little speed-up
  706. * will help.
  707. */
  708. Lisp_Object p, q, nil = C_nil;
  709. Lisp_Object *sp = stack, *sl = stacklimit;
  710. Header h;
  711. int32 i;
  712. *++sp = (Lisp_Object)NULL;
  713. top:
  714. /*
  715. * normally here pp is a pointer to a Lisp_Object and hence an even
  716. * number - I exploit this so that if I find an odd number stacked I
  717. * view it as indicating a return into a vector...
  718. */
  719. if (((int32)pp & 1) != 0)
  720. { i = ((int32)pp) - 1; /* saved value of i */
  721. p = *sp--;
  722. goto in_vector;
  723. }
  724. p = *pp;
  725. if (is_immed_or_cons(p))
  726. {
  727. #ifdef COMMON
  728. if (!is_cons(p) || p == nil || flip_mark_bit_p(p) == nil)
  729. { pp = (Lisp_Object *)(*sp--);
  730. if (pp == NULL) return;
  731. else goto top;
  732. }
  733. #else
  734. if (!is_cons(p))
  735. { pp = (Lisp_Object *)(*sp--);
  736. if (pp == NULL) return;
  737. else goto top;
  738. }
  739. #endif
  740. /*
  741. * Here, and in analagous places, I have to unset the mark bit - this is
  742. * because I set the mark bit on a cons cell early (as I need to) then
  743. * call mark(&car(p)) [in effect], and the effect is that p here sees the
  744. * marked pointer...
  745. */
  746. if (is_marked_p(p)) p = flip_mark_bit_p(p);
  747. q = qcar(p);
  748. if (is_immed_or_cons(q) && !is_cons(q))
  749. { if (is_marked_i(q))
  750. { pp = (Lisp_Object *)(*sp--);
  751. if (pp == NULL) return;
  752. else goto top;
  753. }
  754. qcar(p) = flip_mark_bit_i(q);
  755. pp = &qcdr(p);
  756. goto top;
  757. }
  758. else if (is_marked_p(q))
  759. { pp = (Lisp_Object *)(*sp--);
  760. if (pp == NULL) return;
  761. else goto top;
  762. }
  763. else
  764. { qcar(p) = flip_mark_bit_p(q);
  765. q = qcdr(p);
  766. if (!is_immed(q) && q != nil)
  767. { if (sp >= sl) non_recursive_mark(&qcdr(p));
  768. else *++sp = (Lisp_Object)&qcdr(p);
  769. }
  770. pp = &qcar(p);
  771. goto top;
  772. }
  773. }
  774. /* here we have a vector of some sort */
  775. switch ((int)p & TAG_BITS)
  776. {
  777. default: /* The case-list is exhaustive! */
  778. case TAG_CONS: /* Already processed */
  779. case TAG_FIXNUM: /* Invalid here */
  780. case TAG_ODDS: /* Invalid here */
  781. #ifdef COMMON
  782. case TAG_SFLOAT: /* Invalid here */
  783. #endif
  784. /* Fatal error really called for here */
  785. term_printf("\nBad object in GC (%.8lx)\n", (long)p);
  786. abort();
  787. return;
  788. case TAG_SYMBOL:
  789. if (is_marked_p(p)) p = flip_mark_bit_p(p);
  790. #ifndef COMMON
  791. /*
  792. * NIL is outside the main heap, and so marking it must NOT involve
  793. * the regular pointer-chaining operations.
  794. */
  795. if (p == nil)
  796. { pp = (Lisp_Object *)(*sp--);
  797. if (pp == NULL) return;
  798. else goto top;
  799. }
  800. #endif
  801. h = qheader(p);
  802. if (!is_odds(h)) /* already visited */
  803. { *pp = (Lisp_Object)h;
  804. qheader(p) = (Header)flip_mark_bit_p((Lisp_Object)pp);
  805. pp = (Lisp_Object *)(*sp--);
  806. if (pp == NULL) return;
  807. else goto top;
  808. }
  809. #ifdef DAMAGED_SYMBOLS
  810. term_printf("Symbol at %.8x ", p);
  811. q=qpname(p);
  812. if (is_vector(q) && is_odds(vechdr(q)))
  813. { term_printf("(%.*s)\n", (int)(length_of_header(vechdr(q))-4), &celt(q, 0));
  814. }
  815. else term_printf("(pname not available)\n");
  816. ensure_screen();
  817. #endif
  818. *pp = flip_mark_bit_i(h);
  819. qheader(p) = (Header)flip_mark_bit_p((Lisp_Object)pp);
  820. if (sp >= sl)
  821. { non_recursive_mark(&qvalue(p));
  822. non_recursive_mark(&qenv(p));
  823. non_recursive_mark(&qpname(p));
  824. #ifdef COMMON
  825. non_recursive_mark(&qpackage(p));
  826. #endif
  827. }
  828. else
  829. { q = qvalue(p);
  830. if (!is_immed(q) && q != nil)
  831. *++sp = (Lisp_Object)&qvalue(p);
  832. q = qenv(p);
  833. if (!is_immed(q) && q != nil)
  834. *++sp = (Lisp_Object)&qenv(p);
  835. q = qpname(p);
  836. if (!is_immed(q) && q != nil)
  837. *++sp = (Lisp_Object)&qpname(p);
  838. q = qfastgets(p);
  839. if (!is_immed(q) && q != nil)
  840. *++sp = (Lisp_Object)&qfastgets(p);
  841. #ifdef COMMON
  842. q = qpackage(p);
  843. if (!is_immed(q) && q != nil)
  844. *++sp = (Lisp_Object)&qpackage(p);
  845. #endif
  846. }
  847. pp = &qplist(p); /* iterate into plist not value? */
  848. goto top;
  849. case TAG_NUMBERS:
  850. if (is_marked_p(p)) p = flip_mark_bit_p(p);
  851. h = numhdr(p);
  852. if (!is_odds(h)) /* already visited */
  853. { *pp = (Lisp_Object)h;
  854. numhdr(p) = (Header)flip_mark_bit_p((Lisp_Object)pp);
  855. pp = (Lisp_Object *)(*sp--);
  856. if (pp == NULL) return;
  857. else goto top;
  858. }
  859. *pp = flip_mark_bit_i(h);
  860. numhdr(p) = (Header)flip_mark_bit_p((Lisp_Object)pp);
  861. if (is_bignum_header(h))
  862. { pp = (Lisp_Object *)(*sp--);
  863. if (pp == NULL) return;
  864. else goto top;
  865. }
  866. #ifdef COMMON
  867. q = real_part(p);
  868. if (!is_immed(q))
  869. { if (sp >= sl) non_recursive_mark(&real_part(p));
  870. else *++sp = (Lisp_Object)&real_part(p);
  871. }
  872. pp = (Lisp_Object *)&imag_part(p);
  873. goto top;
  874. #else
  875. term_printf("Bad numeric type found %.8lx\n", (long)h);
  876. abort();
  877. return;
  878. #endif
  879. case TAG_BOXFLOAT:
  880. if (is_marked_p(p)) p = flip_mark_bit_p(p);
  881. h = flthdr(p);
  882. if (!is_odds(h)) /* already visited */
  883. { *pp = (Lisp_Object)h;
  884. flthdr(p) = (Header)flip_mark_bit_p((Lisp_Object)pp);
  885. pp = (Lisp_Object *)(*sp--);
  886. if (pp == NULL) return;
  887. else goto top;
  888. }
  889. *pp = flip_mark_bit_i(h);
  890. flthdr(p) = (Header)flip_mark_bit_p((Lisp_Object)pp);
  891. pp = (Lisp_Object *)(*sp--);
  892. if (pp == NULL) return;
  893. else goto top;
  894. case TAG_VECTOR:
  895. if (is_marked_p(p)) p = flip_mark_bit_p(p);
  896. h = vechdr(p);
  897. if (!is_odds(h)) /* already visited */
  898. { *pp = (Lisp_Object)h;
  899. vechdr(p) = (Header)flip_mark_bit_p((Lisp_Object)pp);
  900. pp = (Lisp_Object *)(*sp--);
  901. if (pp == NULL) return;
  902. else goto top;
  903. }
  904. *pp = flip_mark_bit_i(h);
  905. vechdr(p) = (Header)flip_mark_bit_p((Lisp_Object)pp);
  906. if (vector_holds_binary(h)) /* strings & bitvecs */
  907. { pp = (Lisp_Object *)(*sp--);
  908. if (pp == NULL) return;
  909. else goto top;
  910. }
  911. i = (int32)doubleword_align_up(length_of_header(h));
  912. if (is_mixed_header(h))
  913. i = 16; /* Only use first few pointers */
  914. in_vector:
  915. if (sp >= sl)
  916. { while (i >= 12)
  917. { i -= 4;
  918. non_recursive_mark((Lisp_Object *)((char *)p - TAG_VECTOR + i));
  919. }
  920. }
  921. else
  922. { while (i >= 12)
  923. { i -= 4;
  924. pp = (Lisp_Object *)((char *)p - TAG_VECTOR + i);
  925. q = *pp;
  926. if (!is_immed(q) && q != nil)
  927. { *++sp = p;
  928. *++sp = i + 1;
  929. #ifdef DAMAGED_SYMBOLS
  930. term_printf("Marking item %d of vector %.8x\n", i, p); ensure_screen();
  931. #endif
  932. goto top;
  933. }
  934. }
  935. }
  936. /*
  937. * Because we padded up to an even number of words for the vector in total
  938. * there are always an odd number of pointers to trace, and in particular
  939. * always at least one - so it IS reasonable to iterate on the first item in
  940. * the vector, and there can not be any worries about zero-length vectors
  941. * to hurt me.
  942. */
  943. pp = (Lisp_Object *)((char *)p - TAG_VECTOR + i - 4);
  944. goto top;
  945. }
  946. }
  947. #endif /* DEMO_MODE */
  948. Lisp_Object MS_CDECL Lgc0(Lisp_Object nil, int nargs, ...)
  949. {
  950. argcheck(nargs, 0, "reclaim");
  951. return Lgc(nil, lisp_true);
  952. }
  953. Lisp_Object Lgc(Lisp_Object nil, Lisp_Object a)
  954. {
  955. /*
  956. * If GC is called with a non-nil argument the garbage collection
  957. * will be a full one - otherwise it will be soft and may do hardly
  958. * anything.
  959. */
  960. #ifdef DEMO_MODE
  961. return onevalue(nil);
  962. #else
  963. return reclaim(nil, "user request",
  964. a != nil ? GC_USER_HARD : GC_USER_SOFT, 0);
  965. #endif
  966. }
  967. Lisp_Object Lverbos(Lisp_Object nil, Lisp_Object a)
  968. /*
  969. * (verbos 0) or (verbos nil) silent garbage collection
  970. * (verbos 1) or (verbos t) standard GC messages
  971. * (verbos 2) messages when FASL module loaded
  972. * (verbos 4) extra timing info for GC process
  973. * These bits can be added to get combination effects, except that
  974. * "4" has no effect unless "1" is present.
  975. */
  976. {
  977. int32 code, old_code = verbos_flag;
  978. if (a == nil) code = 0;
  979. else if (is_fixnum(a)) code = int_of_fixnum(a);
  980. else code = 1;
  981. miscflags = (miscflags & ~GC_MSG_BITS) | (code & GC_MSG_BITS);
  982. return onevalue(fixnum_of_int(old_code));
  983. }
  984. CSLbool volatile already_in_gc, tick_on_gc_exit;
  985. CSLbool volatile interrupt_pending, tick_pending, polltick_pending;
  986. Lisp_Object volatile saveheaplimit;
  987. Lisp_Object volatile savevheaplimit;
  988. Lisp_Object volatile savecodelimit;
  989. Lisp_Object * volatile savestacklimit;
  990. static int stop_after_gc = 0;
  991. static int fold_cons_heap(void)
  992. {
  993. /*
  994. * This is amazingly messy because the heap is segmented.
  995. */
  996. nil_as_base
  997. int top_page_number = 0,
  998. bottom_page_number = (int)heap_pages_count - 1;
  999. void *top_page = heap_pages[top_page_number],
  1000. *bottom_page = heap_pages[bottom_page_number];
  1001. char *top_low = (char *)doubleword_align_up((int32)top_page),
  1002. *bottom_low = (char *)doubleword_align_up((int32)bottom_page);
  1003. char *top_start = top_low + CSL_PAGE_SIZE,
  1004. *bottom_start = bottom_low + CSL_PAGE_SIZE;
  1005. char *top_fringe = top_low + qcar(top_low),
  1006. *bottom_fringe = bottom_low + qcar(bottom_low);
  1007. if (bottom_fringe != (char *)fringe)
  1008. { term_printf("disaster wrt heap fringe %.8lx %.8lx\n",
  1009. (long)bottom_fringe, (long)fringe);
  1010. my_exit(EXIT_FAILURE);
  1011. }
  1012. fringe -= sizeof(Cons_Cell);
  1013. for (;;)
  1014. {
  1015. Lisp_Object p;
  1016. /* scan up from fringe to find a busy cell */
  1017. for (;;)
  1018. { fringe += sizeof(Cons_Cell);
  1019. if (top_page_number == bottom_page_number &&
  1020. top_start == (char *)fringe)
  1021. /*
  1022. * The cast to (unsigned) on the next line is unexpectedly delicate. The
  1023. * difference between two pointers is of type ptrdiff_t, which is a signed
  1024. * type. If this is implemented as int (and that in turn is a 16 bit value)
  1025. * then the following subtraction can overflow and give a value that appears
  1026. * to have the wrong sign. The implicit widening to (Lisp_Object) could
  1027. * then propagate the sign bit in an unhelpful manner. Going via a variable
  1028. * of type (unsigned) ought to mend things.
  1029. */
  1030. { unsigned int len = (unsigned int)((char *)fringe - top_low);
  1031. qcar(top_low) = (Lisp_Object)len;
  1032. return bottom_page_number;
  1033. }
  1034. if ((char *)fringe >= bottom_start)
  1035. {
  1036. /*
  1037. * If the heap were to be left totally empty this would be WRONG
  1038. */
  1039. bottom_page = heap_pages[--bottom_page_number];
  1040. bottom_low = (char *)doubleword_align_up((int32)bottom_page);
  1041. bottom_start = bottom_low + CSL_PAGE_SIZE;
  1042. fringe = (Lisp_Object)(bottom_low + qcar(bottom_low));
  1043. heaplimit = (Lisp_Object)(bottom_low + SPARE);
  1044. fringe -= sizeof(Cons_Cell);
  1045. #ifdef TICK_STREAM
  1046. /*
  1047. * From time to time in the GC I poll for clock ticks, just to keep
  1048. * responsiveness of the window system up.
  1049. */
  1050. if (tick_on_gc_exit)
  1051. { Lisp_Object nil;
  1052. inject_randomness((int)clock());
  1053. inject_randomness((int)fringe);
  1054. accept_tick();
  1055. nil = C_nil;
  1056. if (exception_pending())
  1057. { stop_after_gc = 1;
  1058. flip_exception();
  1059. }
  1060. tick_on_gc_exit = NO;
  1061. }
  1062. #endif
  1063. continue;
  1064. }
  1065. p = qcar(fringe);
  1066. if (is_immed_or_cons(p) && !is_cons(p))
  1067. { if (is_marked_i(p))
  1068. { qcar(fringe) = flip_mark_bit_i(p);
  1069. break;
  1070. }
  1071. }
  1072. else if (is_marked_p(p))
  1073. { qcar(fringe) = flip_mark_bit_p(p);
  1074. break;
  1075. }
  1076. }
  1077. /* scan down from the top to find a free cell, unmarking is I go */
  1078. for (;;)
  1079. { top_start -= sizeof(Cons_Cell);
  1080. if (top_page_number == bottom_page_number &&
  1081. top_start == (char *)fringe)
  1082. { unsigned int len = (unsigned int)((char *)fringe - top_low);
  1083. qcar(top_low) = (Lisp_Object)len;
  1084. return bottom_page_number;
  1085. }
  1086. if (top_start < top_fringe)
  1087. { top_page_number++;
  1088. top_page = heap_pages[top_page_number];
  1089. top_low = (char *)doubleword_align_up((int32)top_page);
  1090. top_start = top_low + CSL_PAGE_SIZE;
  1091. top_fringe = top_low + qcar(top_low);
  1092. continue;
  1093. }
  1094. p = qcar(top_start);
  1095. if (is_immed_or_cons(p) && !is_cons(p))
  1096. { if (!is_marked_i(p)) break;
  1097. else qcar(top_start) = flip_mark_bit_i(p);
  1098. }
  1099. else if (!is_marked_p(p)) break;
  1100. else qcar(top_start) = flip_mark_bit_p(p);
  1101. }
  1102. /* Now relocate one cell */
  1103. qcar(top_start) = qcar(fringe);
  1104. qcdr(top_start) = qcdr(fringe);
  1105. { Lisp_Object forward = flip_mark_bit_p(top_start + TAG_VECTOR);
  1106. qcar(fringe) = forward;
  1107. qcdr(fringe) = forward;
  1108. }
  1109. }
  1110. }
  1111. static void adjust_vec_heap(void)
  1112. /*
  1113. * This scans over the vector heap working out where each vector
  1114. * is going to get relocated to, and then changing pointers to reflect
  1115. * where the vectors will end up.
  1116. */
  1117. {
  1118. Lisp_Object nil = C_nil;
  1119. int32 page_number, new_page_number = 0;
  1120. void *new_page = vheap_pages[0];
  1121. char *new_low = (char *)doubleword_align_up((int32)new_page);
  1122. char *new_high = new_low + (CSL_PAGE_SIZE - 8);
  1123. char *p = new_low + 8;
  1124. for (page_number = 0; page_number < vheap_pages_count; page_number++)
  1125. { void *page = vheap_pages[page_number];
  1126. char *low = (char *)doubleword_align_up((int32)page);
  1127. char *fr = low + qcar(low);
  1128. #ifdef TICK_STREAM
  1129. if (tick_on_gc_exit)
  1130. {
  1131. inject_randomness((int)clock());
  1132. inject_randomness((int)fr);
  1133. accept_tick();
  1134. tick_on_gc_exit = NO;
  1135. }
  1136. #endif
  1137. *(Lisp_Object *)fr = nil;
  1138. low += 8;
  1139. for (;;)
  1140. { Header h;
  1141. Lisp_Object h1;
  1142. char *p1;
  1143. int32 l;
  1144. unsigned int free;
  1145. while (is_odds(h = *(Header *)low))
  1146. { if (is_symbol_header(h)) low += symhdr_length;
  1147. else low += doubleword_align_up(length_of_header(h));
  1148. }
  1149. if (low >= fr) break;
  1150. h1 = h;
  1151. while (!is_odds(h1))
  1152. { Lisp_Object h2 = *(Lisp_Object *)clear_mark_bit_p(h1);
  1153. if (is_vector(h2))
  1154. /* forwarding pointer for relocated cons cell */
  1155. h1 = (Lisp_Object)((char *)h2 - TAG_VECTOR + (h1 & 4));
  1156. else h1 = h2;
  1157. }
  1158. if (is_symbol_header(h1)) l = symhdr_length;
  1159. else l = doubleword_align_up(length_of_header(h1));
  1160. /*
  1161. * I subtract the pointers (new_high - p) into an unsigned int because
  1162. * on a 16-bit machine that might be vital! The type ptrdiff_t is a signed
  1163. * type and in bad cases the subtraction might overflow.
  1164. */
  1165. free = (unsigned int)(new_high - p);
  1166. if (l > (int32)free)
  1167. { new_page_number++;
  1168. new_page = vheap_pages[new_page_number];
  1169. new_low = (char *)doubleword_align_up((int32)new_page);
  1170. new_high = new_low + (CSL_PAGE_SIZE - 8);
  1171. p = new_low + 8;
  1172. }
  1173. /*
  1174. * Because I did not have enough bits to store the critical information
  1175. * somewhere nicer I have to reconstruct the tag bits to go with the
  1176. * vector out of the header word associated with it.
  1177. * Here is had BETTER be a vector!
  1178. */
  1179. if (is_symbol_header(h1)) p1 = p + TAG_SYMBOL;
  1180. else if (is_numbers_header(h1)) p1 = p + TAG_NUMBERS;
  1181. else if (is_boxfloat_header(h1)) p1 = p + TAG_BOXFLOAT;
  1182. else p1 = p + TAG_VECTOR;
  1183. while (!is_odds(h))
  1184. { h = clear_mark_bit_p(h);
  1185. h1 = *(Lisp_Object *)h;
  1186. /*
  1187. * The two above lines fail if amalgamated - both on Zortech C 3.0.1 and
  1188. * on a VAX/VMS C compiler. Hence two lines of code where once I had one.
  1189. */
  1190. if (is_vector(h1))
  1191. h = (Lisp_Object)((char *)h1 - TAG_VECTOR + (h & 4));
  1192. else
  1193. { *(Lisp_Object *)h = (Lisp_Object)p1;
  1194. h = h1;
  1195. }
  1196. }
  1197. *(Lisp_Object *)low = set_mark_bit_h(h);
  1198. low += l;
  1199. p += l;
  1200. if (low >= fr) break;
  1201. }
  1202. }
  1203. }
  1204. static void move_vec_heap(void)
  1205. /*
  1206. * This moves data down in the vector heap, supposing that all pointer
  1207. * relocation will be dealt with elsewhere. Calculations made here must remain
  1208. * in step with those in adjust_vecheap.
  1209. */
  1210. {
  1211. nil_as_base
  1212. int32 page_number, new_page_number = 0;
  1213. void *new_page = vheap_pages[0];
  1214. char *new_low = (char *)doubleword_align_up((int32)new_page);
  1215. char *new_high = new_low + (CSL_PAGE_SIZE - 8);
  1216. char *p = new_low + 8;
  1217. for (page_number = 0; page_number < vheap_pages_count; page_number++)
  1218. { void *page = vheap_pages[page_number];
  1219. char *low = (char *)doubleword_align_up((int32)page);
  1220. char *fr = low + qcar(low);
  1221. #ifdef TICK_STREAM
  1222. if (tick_on_gc_exit)
  1223. {
  1224. inject_randomness((int)clock());
  1225. inject_randomness((int)fr);
  1226. accept_tick();
  1227. tick_on_gc_exit = NO;
  1228. }
  1229. #endif
  1230. *(Lisp_Object *)fr = set_mark_bit_h(TAG_ODDS + (8<<10));
  1231. low += 8;
  1232. for (;;)
  1233. { Header h;
  1234. int32 l;
  1235. unsigned int free;
  1236. while (!is_marked_h(h = *(Header *)low))
  1237. if (is_symbol_header(h)) low += symhdr_length;
  1238. else low += doubleword_align_up(length_of_header(h));
  1239. if (low >= fr) break;
  1240. if (is_symbol_header(h)) l = symhdr_length;
  1241. else l = doubleword_align_up(length_of_header(h));
  1242. free = (unsigned int)(new_high - p);
  1243. if (l > (int32)free)
  1244. { unsigned int len = (unsigned int)(p - new_low);
  1245. *(int32 *)new_low = (int32)len;
  1246. /*
  1247. * I fill the end of the page with zero words so that the data there is
  1248. * definite in value, and to help file-compression when I dump a heap
  1249. * image.
  1250. */
  1251. #ifdef CLEAR_OUT_MEMORY
  1252. while (free != 0)
  1253. { *(int32 *)p = 0;
  1254. p += 4;
  1255. free -= 4;
  1256. }
  1257. #endif
  1258. new_page_number++;
  1259. new_page = vheap_pages[new_page_number];
  1260. new_low = (char *)doubleword_align_up((int32)new_page);
  1261. new_high = new_low + (CSL_PAGE_SIZE - 8);
  1262. p = new_low + 8;
  1263. }
  1264. *(Lisp_Object *)p = clear_mark_bit_h(h);
  1265. while ((l -= 4) != 0)
  1266. { p += 4;
  1267. low += 4;
  1268. *(int32 *)p = *(int32 *)low;
  1269. }
  1270. p += 4;
  1271. low += 4;
  1272. }
  1273. }
  1274. { unsigned int len = (unsigned int)(p - new_low);
  1275. #ifdef CLEAR_OUT_MEMORY
  1276. unsigned int free = (unsigned int)(new_high - p);
  1277. #endif
  1278. *(int32 *)new_low = (int32)len;
  1279. #ifdef CLEAR_OUT_MEMORY
  1280. while (free != 0)
  1281. { *(int32 *)p = 0;
  1282. p += 4;
  1283. free -= 4;
  1284. }
  1285. #endif
  1286. }
  1287. vfringe = (Lisp_Object)p;
  1288. vheaplimit = (Lisp_Object)(new_low + (CSL_PAGE_SIZE - 8));
  1289. new_page_number++;
  1290. while (vheap_pages_count > new_page_number)
  1291. pages[pages_count++] = vheap_pages[--vheap_pages_count];
  1292. }
  1293. static int compress_heap(void)
  1294. {
  1295. int n = fold_cons_heap();
  1296. adjust_vec_heap();
  1297. move_vec_heap();
  1298. return n;
  1299. }
  1300. static void relocate(Lisp_Object *cp)
  1301. /*
  1302. * If p is a pointer to a cons cell that has been moved, fix it up.
  1303. */
  1304. {
  1305. Lisp_Object nil = C_nil,
  1306. p = (*cp); /* BEWARE "p =* cp;" anachronism here! */
  1307. if (p == nil) return; /* nil is separate from the main heap */
  1308. else if (is_cons(p))
  1309. { Lisp_Object p1;
  1310. p1 = qcar(p);
  1311. if (is_vector(p1) && is_marked_p(p1))
  1312. *cp = clear_mark_bit_p(p1 - TAG_VECTOR + TAG_CONS);
  1313. }
  1314. }
  1315. static void relocate_consheap(int bottom_page_number)
  1316. {
  1317. int page_number;
  1318. for (page_number = 0; page_number <= bottom_page_number; page_number++)
  1319. { void *page = heap_pages[page_number];
  1320. char *low = (char *)doubleword_align_up((int32)page);
  1321. char *start = low + CSL_PAGE_SIZE;
  1322. char *fr = low + qcar(low);
  1323. #ifdef TICK_STREAM
  1324. if (tick_on_gc_exit)
  1325. {
  1326. inject_randomness((int)clock());
  1327. inject_randomness((int)fr);
  1328. accept_tick();
  1329. tick_on_gc_exit = NO;
  1330. }
  1331. #endif
  1332. while (fr < start)
  1333. { relocate((Lisp_Object *)fr);
  1334. fr += sizeof(Lisp_Object);
  1335. cons_cells += 4;
  1336. }
  1337. }
  1338. }
  1339. static void relocate_vecheap(void)
  1340. {
  1341. int32 page_number, i;
  1342. for (page_number = 0; page_number < vheap_pages_count; page_number++)
  1343. { void *page = vheap_pages[page_number];
  1344. char *low = (char *)doubleword_align_up((int32)page);
  1345. char *fr = low + qcar(low);
  1346. #ifdef TICK_STREAM
  1347. if (tick_on_gc_exit)
  1348. {
  1349. inject_randomness((int)clock());
  1350. inject_randomness((int)fr);
  1351. accept_tick();
  1352. tick_on_gc_exit = NO;
  1353. }
  1354. #endif
  1355. low += 8;
  1356. while (low < fr)
  1357. { Header h = *(Header *)low;
  1358. if (is_symbol_header(h))
  1359. { Symbol_Head *s = (Symbol_Head *)low;
  1360. relocate(&(s->value));
  1361. relocate(&(s->env));
  1362. /*
  1363. * To keep track of literal vectors I suppose here that they are never shared,
  1364. * and I then account for things that are either V or (B . V) in an environment
  1365. * cell, where B is binary code and V is a vector.
  1366. */
  1367. { Lisp_Object e = s->env;
  1368. if (is_cons(e) && is_bps(qcar(e))) e = qcdr(e);
  1369. if (is_vector(e))
  1370. litvecs += doubleword_align_up(
  1371. length_of_header(vechdr(e)));
  1372. }
  1373. /* relocate(&(s->pname)); can never be a cons cell */
  1374. relocate(&(s->plist));
  1375. relocate(&(s->fastgets));
  1376. { Lisp_Object e = s->fastgets;
  1377. if (is_vector(e))
  1378. getvecs += doubleword_align_up(
  1379. length_of_header(vechdr(e)));
  1380. }
  1381. #ifdef COMMON
  1382. relocate(&(s->package));
  1383. #endif
  1384. low += symhdr_length;
  1385. symbol_heads += symhdr_length;
  1386. continue;
  1387. }
  1388. else switch (type_of_header(h))
  1389. {
  1390. #ifdef COMMON
  1391. case TYPE_RATNUM:
  1392. case TYPE_COMPLEX_NUM:
  1393. relocate((Lisp_Object *)(low+4));
  1394. relocate((Lisp_Object *)(low+8));
  1395. other_mem += 8;
  1396. break;
  1397. #endif
  1398. case TYPE_MIXED1:
  1399. case TYPE_MIXED2:
  1400. case TYPE_MIXED3:
  1401. case TYPE_STREAM:
  1402. for (i=4; i<16; i+=4)
  1403. relocate((Lisp_Object *)(low+i));
  1404. other_mem += doubleword_align_up(length_of_header(h));
  1405. break;
  1406. case TYPE_HASH:
  1407. case TYPE_SIMPLE_VEC:
  1408. case TYPE_ARRAY:
  1409. case TYPE_STRUCTURE:
  1410. for (i=4; i<doubleword_align_up(length_of_header(h)); i+=4)
  1411. relocate((Lisp_Object *)(low+i));
  1412. if (type_of_header(h) == TYPE_SIMPLE_VEC)
  1413. user_vectors += doubleword_align_up(length_of_header(h));
  1414. else other_mem += doubleword_align_up(length_of_header(h));
  1415. break;
  1416. case TYPE_STRING:
  1417. strings += doubleword_align_up(length_of_header(h));
  1418. break;
  1419. case TYPE_BIGNUM:
  1420. big_numbers += doubleword_align_up(length_of_header(h));
  1421. break;
  1422. #ifdef COMMON
  1423. case TYPE_SINGLE_FLOAT:
  1424. case TYPE_LONG_FLOAT:
  1425. #endif
  1426. case TYPE_DOUBLE_FLOAT:
  1427. box_floats += doubleword_align_up(length_of_header(h));
  1428. break;
  1429. default:
  1430. break;
  1431. }
  1432. low += doubleword_align_up(length_of_header(h));
  1433. }
  1434. }
  1435. }
  1436. static void abandon_heap_pages(int bottom_page_number)
  1437. {
  1438. bottom_page_number++;
  1439. while (heap_pages_count > bottom_page_number)
  1440. pages[pages_count++] = heap_pages[--heap_pages_count];
  1441. }
  1442. static void zero_out(void *p)
  1443. {
  1444. char *p1 = (char *)doubleword_align_up((int32)p);
  1445. memset(p1, 0, CSL_PAGE_SIZE);
  1446. }
  1447. #ifndef NO_COPYING_GC
  1448. /*
  1449. * You may like to observe how much more compact the code for the copying
  1450. * garbage collector is when compared with the mark/slide mess. It is
  1451. * naturally and easily non-recursive and does not get involved in any
  1452. * over-dubious punning on bit-patterns... It just requires a lot of spare
  1453. * memory for the new semi-space.
  1454. */
  1455. static int32 trailing_heap_pages_count,
  1456. trailing_vheap_pages_count;
  1457. static void copy(Lisp_Object *p)
  1458. /*
  1459. * This copies the object pointed at by p from the old to the new semi-space,
  1460. * and returns a copy to the pointer. If scans the copied material to copy
  1461. * all relevent sub-structures to the new semi-space.
  1462. */
  1463. {
  1464. Lisp_Object nil = C_nil;
  1465. char *fr = (char *)fringe, *vfr = (char *)vfringe;
  1466. char *tr_fr = fr, *tr_vfr = vfr;
  1467. void *p1;
  1468. #define CONT 0
  1469. #define DONE_CAR -1
  1470. #define DONE_VALUE -2
  1471. #define DONE_ENV -3
  1472. #define DONE_PNAME -4
  1473. #define DONE_PLIST -5
  1474. #define DONE_FASTGETS -6
  1475. int32 next = CONT;
  1476. char *tr;
  1477. #ifdef DEBUG_GC
  1478. term_printf("Copy [%.8lx] %.8lx\n", (long)p, (long)*p);
  1479. #endif
  1480. /*
  1481. * The code here is a simulation of multiple procedure calls to the
  1482. * code that copies a single object. What might otherwise have been
  1483. * a "return address" in the calls is handled by the variable "next" which
  1484. * takes positive values while copying vectors, and negative ones in
  1485. * the more common cases. I use "for (;;)" blocks a lot so that I can
  1486. * use "break" and "continue" to leap around in the code - maybe I
  1487. * would do better to be honest and use regular labels and "goto"
  1488. * statements.
  1489. */
  1490. for (;;)
  1491. {
  1492. /*
  1493. * Copy one object, pointed at by p, from the old semi-space into the new
  1494. * one.
  1495. */
  1496. Lisp_Object a = *p;
  1497. #ifdef DEBUG_GC
  1498. term_printf("Next copy [%.8lx] %.8lx\n", (long)p, (long)*p);
  1499. #endif
  1500. for (;;)
  1501. {
  1502. if (a == nil) break; /* common and cheap enough to test here */
  1503. else if (is_immed_or_cons(a))
  1504. { if (is_cons(a))
  1505. {
  1506. Lisp_Object w;
  1507. w = qcar(a);
  1508. if (is_cons(w) && is_marked_p(w)) /* a forwarding address */
  1509. { *p = flip_mark_bit_p(w);
  1510. break;
  1511. }
  1512. fr = fr - sizeof(Cons_Cell);
  1513. cons_cells += 8;
  1514. /*
  1515. * When I am doing regular calculation I leave myself a bunch of spare
  1516. * words (size SPARE bytes) so that I can afford to do several cons operations
  1517. * between tests. Here I do careful tests on every step, and so I can
  1518. * sail much closer to the wind wrt filling up space.
  1519. */
  1520. if (fr <= (char *)heaplimit - SPARE + 32)
  1521. { char *hl = (char *)heaplimit;
  1522. void *p;
  1523. unsigned int len = (unsigned int)(fr - (hl - SPARE) + 8);
  1524. qcar(hl - SPARE) = (Lisp_Object)len;
  1525. qcar(fr) = SPID_GCMARK;
  1526. if (pages_count == 0)
  1527. { abort();
  1528. return;
  1529. }
  1530. p = pages[--pages_count];
  1531. zero_out(p);
  1532. new_heap_pages[new_heap_pages_count++] = p;
  1533. heaplimit = doubleword_align_up((int32)p);
  1534. hl = (char *)heaplimit;
  1535. qcar(heaplimit) = CSL_PAGE_SIZE;
  1536. fr = hl + CSL_PAGE_SIZE - sizeof(Cons_Cell);
  1537. heaplimit = (Lisp_Object)(hl + SPARE);
  1538. }
  1539. qcar(fr) = w;
  1540. qcdr(fr) = qcdr(a);
  1541. *p = w = (Lisp_Object)(fr + TAG_CONS);
  1542. qcar(a) = flip_mark_bit_p(w);
  1543. break;
  1544. }
  1545. else if (is_bps(a))
  1546. { char *d = data_of_bps(a) - 4, *rr;
  1547. int32 alloc_size;
  1548. Header h = *(Header *)d;
  1549. int32 len;
  1550. if (is_bps(h)) /* Replacement handle in header field? */
  1551. { *p = h ;
  1552. break;
  1553. }
  1554. len = length_of_header(h);
  1555. alloc_size = (int32)doubleword_align_up(len);
  1556. bytestreams += alloc_size;
  1557. for (;;)
  1558. { char *cf = (char *)codefringe,
  1559. *cl = (char *)codelimit;
  1560. unsigned int free = (unsigned int)(cf - cl);
  1561. if (alloc_size > (int32)free)
  1562. {
  1563. void *p;
  1564. if (codelimit != 0)
  1565. { unsigned int len = (unsigned int)(cf - (cl - 8));
  1566. qcar(cl - 8) = (Lisp_Object)len;
  1567. }
  1568. if (pages_count == 0)
  1569. { abort();
  1570. return;
  1571. }
  1572. p = pages[--pages_count];
  1573. zero_out(p);
  1574. new_bps_pages[new_bps_pages_count++] = p;
  1575. cl = (char *)doubleword_align_up((int32)p);
  1576. codefringe = (Lisp_Object)(cl + CSL_PAGE_SIZE);
  1577. codelimit = (Lisp_Object)(cl + 8);
  1578. continue;
  1579. }
  1580. rr = cf - alloc_size;
  1581. codefringe = (Lisp_Object)rr;
  1582. *(Header *)d = *p = TAG_BPS +
  1583. (((int32)(rr - cl + 12) &
  1584. (PAGE_POWER_OF_TWO-4)) << 6) +
  1585. ((new_bps_pages_count-1)<<(PAGE_BITS+6));
  1586. /* Wow! How obscure!! */
  1587. *(Header *)rr = h;
  1588. { unsigned32 *s = (unsigned32 *)d;
  1589. unsigned32 *d = (unsigned32 *)rr;
  1590. *++d = *++s;
  1591. while ((alloc_size -= 8) != 0)
  1592. { *++d = *++s;
  1593. *++d = *++s;
  1594. }
  1595. }
  1596. break;
  1597. }
  1598. break;
  1599. }
  1600. else break; /* Immediate data drops out here */
  1601. }
  1602. else /* Here I have a symbol or vector */
  1603. { Header h;
  1604. int tag;
  1605. int32 len;
  1606. tag = ((int)a) & TAG_BITS;
  1607. a = (Lisp_Object)((char *)a - tag);
  1608. h = *(Header *)a;
  1609. #ifdef DEBUG_GC
  1610. term_printf("Header is %.8lx\n", (long)h);
  1611. #endif
  1612. if (!is_odds(h))
  1613. { *p = h;
  1614. break;
  1615. }
  1616. if (tag == TAG_SYMBOL)
  1617. len = symhdr_length, symbol_heads += symhdr_length;
  1618. else
  1619. { len = doubleword_align_up(length_of_header(h));
  1620. switch (type_of_header(h))
  1621. {
  1622. case TYPE_STRING:
  1623. strings += len; break;
  1624. case TYPE_BIGNUM:
  1625. big_numbers += len; break;
  1626. #ifdef COMMON
  1627. case TYPE_SINGLE_FLOAT:
  1628. case TYPE_LONG_FLOAT:
  1629. #endif
  1630. case TYPE_DOUBLE_FLOAT:
  1631. box_floats += len; break;
  1632. case TYPE_SIMPLE_VEC:
  1633. user_vectors += len; break;
  1634. default:
  1635. other_mem += len; break;
  1636. }
  1637. }
  1638. for (;;)
  1639. { char *vl = (char *)vheaplimit;
  1640. unsigned int free = (unsigned int)(vl - vfr);
  1641. if (len > (int32)free)
  1642. { unsigned int free1 = (unsigned int)(vfr - (vl - (CSL_PAGE_SIZE - 8)));
  1643. qcar(vl - (CSL_PAGE_SIZE - 8)) = (Lisp_Object)free1;
  1644. qcar(vfr) = 0; /* sentinel value */
  1645. if (pages_count == 0)
  1646. { abort();
  1647. return;
  1648. }
  1649. p1 = pages[--pages_count];
  1650. zero_out(p1);
  1651. new_vheap_pages[new_vheap_pages_count++] = p1;
  1652. vfr = (char *)doubleword_align_up((int32)p1) + 8;
  1653. vl = vfr + (CSL_PAGE_SIZE - 16);
  1654. vheaplimit = (Lisp_Object)vl;
  1655. free1 = (unsigned int)(vfr - (vl - (CSL_PAGE_SIZE - 8)));
  1656. qcar(vl - (CSL_PAGE_SIZE - 8)) = (Lisp_Object)free1;
  1657. continue;
  1658. }
  1659. *(Lisp_Object *)a = *p = (Lisp_Object)(vfr + tag);
  1660. *(Header *)vfr = h;
  1661. { Lisp_Object *s = (Lisp_Object *)a;
  1662. Lisp_Object *d = (Lisp_Object *)vfr;
  1663. vfr = vfr + len;
  1664. *++d = *++s;
  1665. while ((len -= 8) != 0)
  1666. { *++d = *++s;
  1667. *++d = *++s;
  1668. }
  1669. }
  1670. break;
  1671. }
  1672. break;
  1673. }
  1674. }
  1675. /*
  1676. * Now I have copied one object - the next thing to do is to scan to see
  1677. * if any further items are in the new space, and if so I will copy
  1678. * their offspring.
  1679. */
  1680. for (;;)
  1681. {
  1682. switch (next)
  1683. {
  1684. case CONT:
  1685. if (tr_fr != fr)
  1686. { tr_fr = tr_fr - sizeof(Cons_Cell);
  1687. if (qcar(tr_fr) == SPID_GCMARK)
  1688. { char *w;
  1689. p1 = new_heap_pages[trailing_heap_pages_count++];
  1690. w = (char *)doubleword_align_up((int32)p1);
  1691. tr_fr = w + (CSL_PAGE_SIZE - sizeof(Cons_Cell));
  1692. }
  1693. next = DONE_CAR;
  1694. p = &qcar(tr_fr);
  1695. break; /* Takes me to the outer loop */
  1696. }
  1697. else if (tr_vfr != vfr)
  1698. { Header h;
  1699. h = *(Header *)tr_vfr;
  1700. if (h == 0)
  1701. { char *w;
  1702. p1 = new_vheap_pages[trailing_vheap_pages_count++];
  1703. w = (char *)doubleword_align_up((int32)p1);
  1704. tr_vfr = w + 8;
  1705. h = *(Header *)tr_vfr;
  1706. }
  1707. if (is_symbol_header(h))
  1708. { next = DONE_VALUE;
  1709. p = &(((Symbol_Head *)tr_vfr)->value);
  1710. break;
  1711. }
  1712. else
  1713. { int32 len = doubleword_align_up(length_of_header(h));
  1714. tr = tr_vfr;
  1715. tr_vfr = tr_vfr + len;
  1716. switch (type_of_header(h))
  1717. {
  1718. #ifdef COMMON
  1719. case TYPE_SINGLE_FLOAT:
  1720. case TYPE_LONG_FLOAT:
  1721. #endif
  1722. case TYPE_DOUBLE_FLOAT:
  1723. case TYPE_BIGNUM:
  1724. continue;
  1725. case TYPE_MIXED1: case TYPE_MIXED2:
  1726. case TYPE_MIXED3: case TYPE_STREAM:
  1727. next = 8;
  1728. break;
  1729. /*
  1730. * There is a slight delight here. The test "vector_holds_binary" is only
  1731. * applicable if the header to be checked is a header of a genuine vector,
  1732. * ie something that would have TAG_VECTOR in the pointer to it. But here
  1733. * various numeric data types also live in the vector heap, so I need to
  1734. * separate them out explicitly. The switch block here does slightly more than
  1735. * it actually HAS to, since the vector_holds_binary test would happen to
  1736. * deal with several of the numeric types "by accident", but I feel that
  1737. * the security of listing them as separate cases is more important than the
  1738. * minor speed-up that might come from exploiting such marginal behaviour.
  1739. */
  1740. default:
  1741. if (vector_holds_binary(h)) continue;
  1742. #ifdef COMMON
  1743. case TYPE_RATNUM:
  1744. case TYPE_COMPLEX_NUM:
  1745. #endif
  1746. next = len - 8;
  1747. break;
  1748. }
  1749. p = (Lisp_Object *)(tr + next + 4);
  1750. break;
  1751. }
  1752. }
  1753. else
  1754. { fringe = (Lisp_Object)fr;
  1755. vfringe = (Lisp_Object)vfr;
  1756. return; /* Final exit when all has been copied */
  1757. }
  1758. case DONE_CAR:
  1759. next = CONT;
  1760. p = &qcdr(tr_fr);
  1761. break;
  1762. case DONE_VALUE:
  1763. next = DONE_ENV;
  1764. p = &(((Symbol_Head *)tr_vfr)->env);
  1765. break;
  1766. case DONE_ENV:
  1767. next = DONE_FASTGETS;
  1768. p = &(((Symbol_Head *)tr_vfr)->fastgets);
  1769. break;
  1770. case DONE_FASTGETS:
  1771. next = DONE_PNAME;
  1772. p = &(((Symbol_Head *)tr_vfr)->pname);
  1773. break;
  1774. case DONE_PNAME:
  1775. #ifndef COMMON
  1776. next = CONT;
  1777. p = &(((Symbol_Head *)tr_vfr)->plist);
  1778. tr_vfr = tr_vfr + symhdr_length;
  1779. break;
  1780. #else
  1781. next = DONE_PLIST;
  1782. p = &(((Symbol_Head *)tr_vfr)->plist);
  1783. break;
  1784. case DONE_PLIST:
  1785. next = CONT;
  1786. p = &(((Symbol_Head *)tr_vfr)->package);
  1787. tr_vfr = tr_vfr + symhdr_length;
  1788. break;
  1789. #endif
  1790. default:
  1791. p = (Lisp_Object *)(tr + next);
  1792. next -= 4;
  1793. break;
  1794. }
  1795. break;
  1796. }
  1797. }
  1798. }
  1799. #endif /* NO_COPYING_GC */
  1800. #ifndef DEMO_MODE
  1801. typedef struct mapstore_item
  1802. {
  1803. double w;
  1804. double n;
  1805. unsigned32 n1;
  1806. Lisp_Object p;
  1807. } mapstore_item;
  1808. static int MS_CDECL profile_cf(const void *a, const void *b)
  1809. {
  1810. mapstore_item *aa = (mapstore_item *)a,
  1811. *bb = (mapstore_item *)b;
  1812. if (aa->w == bb->w) return 0;
  1813. else if (aa->w < bb->w) return 1;
  1814. else return -1;
  1815. }
  1816. #endif
  1817. Lisp_Object Lmapstore(Lisp_Object nil, Lisp_Object a)
  1818. /*
  1819. * Argument controls what happens:
  1820. * nil or 0 print statistics and reset to zero
  1821. * 1 print, but do not reset
  1822. * 2 return list of stats, reset to zero
  1823. * 3 return list, do not reset
  1824. * 4 reset to zero, do not print, return nil
  1825. */
  1826. {
  1827. #ifdef DEMO_MODE
  1828. return onevalue(nil);
  1829. #else
  1830. int pass, what;
  1831. int32 j, gcn;
  1832. double itotal = 0.0, total = 0.0;
  1833. Lisp_Object res = nil;
  1834. mapstore_item *buff;
  1835. int32 buffp, buffn;
  1836. if (a == nil) a = fixnum_of_int(0);
  1837. if (is_fixnum(a)) what = int_of_fixnum(a);
  1838. else what = 0;
  1839. if ((what & 6) == 0)
  1840. { buff = (mapstore_item *)malloc(100*sizeof(mapstore_item));
  1841. if (buff == NULL) return onevalue(nil); /* fail */
  1842. buffp = 0;
  1843. buffn = 100;
  1844. }
  1845. if ((what & 2) != 0)
  1846. { Lgc0(nil, 0); /* Force GC at start to avoid one in the middle */
  1847. nil = C_nil;
  1848. if (exception_pending()) return nil;
  1849. gcn = gc_number;
  1850. }
  1851. #ifdef PROFILED
  1852. /*
  1853. * PROFILED is intended to be defined if we were compiled with a -p option,
  1854. * and we take system dependent action to dump out results (e.g. on some systems
  1855. * it may be useful to invoke monitor() or moncontrol() here.
  1856. */
  1857. #ifdef SHOW_COUNTS_AVAILABLE
  1858. show_counts();
  1859. write_profile("counts"); /* Useful if -px option to compiler */
  1860. #endif
  1861. #endif /* PROFILED */
  1862. { char *vf = (char *)vfringe,
  1863. *vl = (char *)vheaplimit;
  1864. unsigned int len = (unsigned int)(vf - (vl - (CSL_PAGE_SIZE - 8)));
  1865. /*
  1866. * Set up the current page so I can tell where the active data is.
  1867. */
  1868. qcar(vl - (CSL_PAGE_SIZE - 8)) = (Lisp_Object)len;
  1869. }
  1870. for (pass=0; pass<2; pass++)
  1871. { for (j=0; j<vheap_pages_count; j++)
  1872. { void *page = vheap_pages[j];
  1873. char *low = (char *)doubleword_align_up((int32)page);
  1874. char *high = low + qcar(low);
  1875. low += 8;
  1876. while (low<high)
  1877. { Header h = *(Header *)low;
  1878. if (is_symbol_header(h))
  1879. { Lisp_Object e = qenv(low + TAG_SYMBOL);
  1880. int32 clen = 0;
  1881. unsigned32 n;
  1882. if (is_cons(e))
  1883. { e = qcar(e);
  1884. if (is_bps(e))
  1885. { Header ch = *(Header *)(data_of_bps(e) - 4);
  1886. clen = length_of_header(ch);
  1887. }
  1888. }
  1889. n = qcount(low + TAG_SYMBOL);
  1890. if (n != 0 && clen != 0)
  1891. { double w = (double)n/(double)clen;
  1892. /*
  1893. * Here I want a measure that will give a good idea of how worthwhile it
  1894. * would be to compile the given function into C - what I have chosen is
  1895. * a count of bytecodes executed scaled by the length
  1896. * of the bytestream code defining the function. This will cause "good value"
  1897. * cases to show up best. I scale this relative to the total across all
  1898. * functions recorded to make the numbers less sensitive to details of
  1899. * how I generate test cases. For interest I also display the proportion
  1900. * of actual bytecodes interpreted. In each case I record these out of
  1901. * a total of 100.0 (percent) to give comfortable ranges of numbers to admire.
  1902. */
  1903. if (pass == 0) itotal += (double)n, total += w;
  1904. else
  1905. { if (w/total > 0.00001 ||
  1906. (double)n/itotal > 0.0001)
  1907. { if ((what & 6) == 0)
  1908. { if (buffp == buffn)
  1909. { buffn += 100;
  1910. buff = (mapstore_item *)
  1911. realloc((void *)buff,
  1912. sizeof(mapstore_item)*buffn);
  1913. if (buff == NULL) return onevalue(nil);
  1914. }
  1915. buff[buffp].w = 100.0*w/total;
  1916. buff[buffp].n = 100.0*(double)n/itotal;
  1917. buff[buffp].n1 = n;
  1918. buff[buffp].p = (Lisp_Object)(low + TAG_SYMBOL);
  1919. buffp++;
  1920. }
  1921. if ((what & 2) != 0)
  1922. { Lisp_Object w1;
  1923. /* Result is a list of items ((name size bytes-executed) ...).
  1924. * You might think that I needed to push res here - but I abort if there
  1925. * is a GC, so it is not necessary after all.
  1926. */
  1927. w1 = list3((Lisp_Object)(low + TAG_SYMBOL),
  1928. fixnum_of_int(clen),
  1929. fixnum_of_int(n));
  1930. nil = C_nil;
  1931. if (exception_pending() || gcn != gc_number)
  1932. return nil;
  1933. res = cons(w1, res);
  1934. nil = C_nil;
  1935. if (exception_pending() || gcn != gc_number)
  1936. return nil;
  1937. }
  1938. }
  1939. /*
  1940. * Reset count unless 1 bit of arg is set
  1941. */
  1942. if ((what & 1) == 0)
  1943. qcount(low + TAG_SYMBOL) = 0;
  1944. }
  1945. }
  1946. low += symhdr_length;
  1947. }
  1948. else low += (int32)doubleword_align_up(length_of_header(h));
  1949. }
  1950. }
  1951. }
  1952. if ((what & 6) == 0)
  1953. { double running = 0.0;
  1954. qsort((void *)buff, buffp, sizeof(buff[0]), profile_cf);
  1955. trace_printf("\n Value %%bytes (So far) Bytecodes Function name\n");
  1956. for (j=0; j<buffp; j++)
  1957. { running += buff[j].n;
  1958. trace_printf("%7.2f %7.2f (%6.2f) %9lu: ",
  1959. buff[j].w, buff[j].n, running, (long unsigned)buff[j].n1);
  1960. prin_to_trace(buff[j].p);
  1961. trace_printf("\n");
  1962. }
  1963. trace_printf("\n");
  1964. free((void *)buff);
  1965. }
  1966. return onevalue(res);
  1967. #endif /* DEMO_MODE */
  1968. }
  1969. Lisp_Object MS_CDECL Lmapstore0(Lisp_Object nil, int nargs, ...)
  1970. {
  1971. argcheck(nargs, 0, "mapstore");
  1972. return Lmapstore(nil, nil);
  1973. }
  1974. static CSLbool reset_limit_registers(int32 vheap_need,
  1975. int32 bps_need, int32 native_need)
  1976. /*
  1977. * returns YES if after resetting the limit registers there was
  1978. * enough space left for me to proceed.
  1979. */
  1980. {
  1981. void *p;
  1982. nil_as_base
  1983. unsigned int len;
  1984. CSLbool full;
  1985. #ifndef NO_COPYING_GC
  1986. if (gc_method)
  1987. full = (pages_count <=
  1988. heap_pages_count + vheap_pages_count +
  1989. bps_pages_count + native_pages_count);
  1990. else
  1991. #endif
  1992. full = (pages_count == 0);
  1993. if (fringe <= heaplimit)
  1994. { if (full) return NO;
  1995. p = pages[--pages_count];
  1996. zero_out(p);
  1997. heap_pages[heap_pages_count++] = p;
  1998. heaplimit = doubleword_align_up((int32)p);
  1999. qcar(heaplimit) = CSL_PAGE_SIZE;
  2000. fringe = (Lisp_Object)((char *)heaplimit + CSL_PAGE_SIZE);
  2001. heaplimit = (Lisp_Object)((char *)heaplimit + SPARE);
  2002. }
  2003. { char *vh = (char *)vheaplimit,
  2004. *vf = (char *)vfringe;
  2005. len = (unsigned int)(vh - vf);
  2006. }
  2007. if (vheap_need > (int32)len)
  2008. { char *vf, *vh;
  2009. if (full) return NO;
  2010. p = pages[--pages_count];
  2011. zero_out(p);
  2012. vheap_pages[vheap_pages_count++] = p;
  2013. vf = (char *)doubleword_align_up((int32)p) + 8;
  2014. vfringe = (Lisp_Object)vf;
  2015. vh = vf + (CSL_PAGE_SIZE - 16);
  2016. vheaplimit = (Lisp_Object)vh;
  2017. len = (unsigned int)(vf - (vh - (CSL_PAGE_SIZE - 8)));
  2018. qcar(vh - (CSL_PAGE_SIZE - 8)) = (Lisp_Object)len;
  2019. }
  2020. { char *cl = (char *)codelimit,
  2021. *cf = (char *)codefringe;
  2022. len = (unsigned int)(cf - cl);
  2023. }
  2024. if (bps_need != 0 && bps_need >= (int32)len)
  2025. { char *cl;
  2026. if (full || bps_pages_count >= MAX_BPS_PAGES - 1) return NO;
  2027. p = pages[--pages_count];
  2028. zero_out(p);
  2029. bps_pages[bps_pages_count++] = p;
  2030. cl = (char *)doubleword_align_up((int32)p);
  2031. codefringe = (Lisp_Object)(cl + CSL_PAGE_SIZE);
  2032. codelimit = (Lisp_Object)(cl + 8);
  2033. }
  2034. if (native_need != 0)
  2035. { if (full || native_pages_count >= MAX_NATIVE_PAGES - 1) return NO;
  2036. p = pages[--pages_count];
  2037. zero_out(p);
  2038. native_pages[native_pages_count++] = p;
  2039. native_fringe = 8;
  2040. }
  2041. return (stack < stacklimit);
  2042. }
  2043. static void tidy_fringes(void)
  2044. /*
  2045. * heaplimit was SPARE bytes above the actual base of the page,
  2046. * so the next line dumps fringe somewhere where it can be found
  2047. * later on when needed while scanning a page of heap. Similarly
  2048. * vfringe is stashed away at the end of its page.
  2049. */
  2050. { nil_as_base
  2051. char *fr = (char *)fringe,
  2052. *vf = (char *)vfringe,
  2053. *cf = (char *)codefringe,
  2054. *hl = (char *)heaplimit,
  2055. *vl = (char *)vheaplimit,
  2056. *cl = (char *)codelimit;
  2057. unsigned int len = (unsigned int)(fr - (hl - SPARE));
  2058. qcar(hl - SPARE) = (Lisp_Object)len;
  2059. len = (unsigned int)(vf - (vl - (CSL_PAGE_SIZE - 8)));
  2060. qcar(vl - (CSL_PAGE_SIZE - 8)) = (Lisp_Object)len;
  2061. if (codelimit != 0)
  2062. { len = (unsigned int)(cf - (cl - 8));
  2063. qcar(cl - 8) = (Lisp_Object)len;
  2064. }
  2065. }
  2066. static void lose_dead_hashtables()
  2067. /*
  2068. * This splices out from the list of hash tables all entries that point to
  2069. * tables that have not been marked or copied this garbage collection.
  2070. */
  2071. {
  2072. Lisp_Object *p = &eq_hash_tables, q, r;
  2073. while ((q = *p) != C_nil)
  2074. { Header h;
  2075. r = qcar(q);
  2076. h = vechdr(r);
  2077. if (is_odds(h) && !is_marked_h(h)) *p = qcdr(q);
  2078. else p = &qcdr(q);
  2079. }
  2080. p = &equal_hash_tables;
  2081. while ((q = *p) != C_nil)
  2082. { Header h;
  2083. r = qcar(q);
  2084. h = vechdr(r);
  2085. if (is_odds(h) && !is_marked_h(h)) *p = qcdr(q);
  2086. else p = &qcdr(q);
  2087. }
  2088. }
  2089. #ifdef DEMO_MODE
  2090. extern CSLbool terminal_pushed;
  2091. void give_up()
  2092. {
  2093. Lisp_Object nil;
  2094. #define m(s) err_printf(s)
  2095. m("\n+++ DEMONSTRATION VERSION OF REDUCE - RESOURCE LIMIT EXCEEDED +++\n");
  2096. m("This version of REDUCE has been provided for testing and\n");
  2097. m("demonstration purposes. It has a built-in cut-out that will\n");
  2098. m("terminate processing after a time that should be sufficient for\n");
  2099. m("various small tests to run, but which will probably stop it\n");
  2100. m("from being useful as a serious tool. You are permitted to copy\n");
  2101. m("the demonstration version and pass it on to friends subject to\n");
  2102. m("not changing it, and in particular neither changing the various\n");
  2103. m("messages it prints nor attempting to circumvent the time-out\n");
  2104. m("mechanism. Full versions of REDUCE are available to run on a\n");
  2105. m("wide range of types of computer, and a machine-readable file\n");
  2106. m("listing suppliers was provided with the documentation that goes\n");
  2107. m("with this version. Some suppliers are:\n");
  2108. m(" Codemist Ltd, Alta, Horsecombe Vale, Combe Down, Bath BA2 5QR,\n");
  2109. m(" England. Phone and fax +44-225-837430,\n");
  2110. m(" http://www.codemist.tc\n");
  2111. m(" Winfried Neun, Konrad-Zuse-Zentrum fuer Informationstechnik Berlin\n");
  2112. m(" Heilbronner Str. 10, D 10711 Berlin-Wilmersdorf, GERMANY\n");
  2113. m(" Phone: +44-30-89604-195 Fax +49-30-89604-125.\n");
  2114. m(" (Codemist provided this version, the ZIB differs slightly)\n");
  2115. m("<Close window/type RETURN to exit>\n");
  2116. #undef m
  2117. nil = C_nil;
  2118. prompt_thing = CHAR_EOF; /* Disables the prompt */
  2119. ensure_screen();
  2120. terminal_pushed = NOT_CHAR;
  2121. tty_count = 0;
  2122. char_from_terminal(0);
  2123. my_exit(EXIT_FAILURE);
  2124. }
  2125. #endif
  2126. Lisp_Object reclaim(Lisp_Object p, char *why, int stg_class, int32 size)
  2127. {
  2128. int32 i;
  2129. clock_t t0, t1, t2, t3;
  2130. int bottom_page_number;
  2131. Lisp_Object *sp, nil = C_nil;
  2132. int32 vheap_need = 0, bps_need = 0, native_need = 0;
  2133. stop_after_gc = 0;
  2134. if (stg_class == GC_VEC) vheap_need = size;
  2135. else if (stg_class == GC_BPS) bps_need = size;
  2136. else if (stg_class == GC_NATIVE) native_need = size;
  2137. already_in_gc = YES;
  2138. #ifdef SOCKETS
  2139. if (socket_server != 0)
  2140. { time_t tt0 = time(NULL);
  2141. t0 = clock();
  2142. tt0 = time(NULL);
  2143. if (t0 > cpu_timeout ||
  2144. tt0 > elapsed_timeout)
  2145. { cpu_timeout = t0 + 20;
  2146. elapsed_timeout = tt0 + 20;
  2147. term_printf("\nSorry: timeout on this session. Closing down\n");
  2148. return Lstop(nil, fixnum_of_int(1));
  2149. }
  2150. }
  2151. #endif
  2152. push_clock(); t0 = base_time;
  2153. #ifdef TICK_STREAM
  2154. if (tick_pending != 0)
  2155. { tick_pending = 0;
  2156. heaplimit = saveheaplimit;
  2157. vheaplimit = savevheaplimit;
  2158. codelimit = savecodelimit;
  2159. stacklimit = savestacklimit;
  2160. tidy_fringes();
  2161. if (stg_class != GC_PRESERVE &&
  2162. stg_class != GC_USER_HARD &&
  2163. reset_limit_registers(vheap_need, bps_need, native_need))
  2164. { already_in_gc = NO;
  2165. tick_on_gc_exit = NO;
  2166. #ifdef POLL_FOR_ATTN
  2167. poll_for_attn();
  2168. nil = C_nil;
  2169. if (exception_pending())
  2170. { pop_clock();
  2171. return nil;
  2172. }
  2173. #endif
  2174. if (interrupt_pending)
  2175. { interrupt_pending = NO;
  2176. pop_clock();
  2177. return interrupted(p);
  2178. }
  2179. else
  2180. {
  2181. inject_randomness((int)clock());
  2182. accept_tick();
  2183. pop_clock();
  2184. return onevalue(p);
  2185. }
  2186. }
  2187. else tick_on_gc_exit = YES;
  2188. }
  2189. else
  2190. #else
  2191. if (interrupt_pending)
  2192. { if (tick_pending)
  2193. { tick_pending = 0;
  2194. heaplimit = saveheaplimit;
  2195. vheaplimit = savevheaplimit;
  2196. codelimit = savecodelimit;
  2197. stacklimit = savestacklimit;
  2198. }
  2199. tidy_fringes();
  2200. interrupt_pending = NO;
  2201. pop_clock();
  2202. return interrupted(p);
  2203. }
  2204. #endif
  2205. { tidy_fringes();
  2206. if (stg_class != GC_PRESERVE &&
  2207. stg_class != GC_USER_HARD &&
  2208. reset_limit_registers(vheap_need, bps_need, native_need))
  2209. { already_in_gc = NO;
  2210. pop_clock();
  2211. return onevalue(p); /* Soft GC */
  2212. }
  2213. }
  2214. if (stack >= stacklimit)
  2215. { stacklimit = &stacklimit[50]; /* Allow a bit of slack */
  2216. pop_clock();
  2217. return error(0, err_stack_overflow);
  2218. }
  2219. #ifdef MEMORY_TRACE
  2220. identify_page_types();
  2221. memory_comment(4);
  2222. #endif
  2223. #ifdef DEMO_MODE
  2224. give_up();
  2225. pop_clock();
  2226. return nil;
  2227. #else
  2228. push(p);
  2229. gc_number++;
  2230. #ifdef WINDOW_SYSTEM
  2231. /*
  2232. * If I have a window system I tell it the current time every so often
  2233. * just to keep things cheery...
  2234. */
  2235. { long int t = (long int)(100.0 * consolidated_time[0]);
  2236. long int gct = (long int)(100.0 * gc_time);
  2237. /* /*
  2238. * I guess that I want garbage collection messages, if any, to
  2239. * be sent to stderr rather than whatever output stream happens to
  2240. * be selected at the time of the garbage collection?
  2241. * At present messages go to the normal output stream, which only makes
  2242. * sense if GC messages are almost always disabled - maybe that will
  2243. * be the case!
  2244. */
  2245. report_time(t, gct);
  2246. if (verbos_flag & 1)
  2247. { freshline_trace();
  2248. trace_printf(
  2249. "+++ Garbage collection %ld (%s) after %ld.%.2ld+%ld.%.2ld seconds\n",
  2250. (long)gc_number, why, t/100, t%100, gct/100, gct%100);
  2251. }
  2252. }
  2253. #else
  2254. if (verbos_flag & 1)
  2255. { long int t = (long int)(100.0 * consolidated_time[0]);
  2256. long int gct = (long int)(100.0 * gc_time);
  2257. /* /* I guess that I want garbage collection messages, if any, to
  2258. * be sent to stderr rather than whatever output stream happens to
  2259. * be selected at the time of the garbage collection?
  2260. * At present messages go to the normal output stream, which only makes
  2261. * sense if GC messages are almost always disabled - maybe that will
  2262. * be the case!
  2263. */
  2264. freshline_trace();
  2265. trace_printf(
  2266. "+++ Garbage collection %ld (%s) after %ld.%.2ld+%ld.%.2ld seconds\n",
  2267. (long)gc_number, why, t/100, t%100, gct/100, gct%100);
  2268. }
  2269. #endif
  2270. /*
  2271. * If things crash really badly maybe I would rather have my output up
  2272. * to date.
  2273. */
  2274. ensure_screen();
  2275. nil = C_nil;
  2276. if (exception_pending())
  2277. { stop_after_gc = 1;
  2278. flip_exception();
  2279. }
  2280. if (spool_file != NULL) fflush(spool_file);
  2281. copy_into_nilseg(NO);
  2282. cons_cells = symbol_heads = strings = user_vectors =
  2283. big_numbers = box_floats = bytestreams = other_mem =
  2284. litvecs = getvecs = 0;
  2285. #ifndef NO_COPYING_GC
  2286. if (gc_method)
  2287. {
  2288. t2 = t1 = t0; /* Time is not split down in this case */
  2289. /*
  2290. * Set up the new half-space initially empty.
  2291. */
  2292. new_heap_pages_count = 0;
  2293. new_vheap_pages_count = 0;
  2294. new_bps_pages_count = 0;
  2295. trailing_heap_pages_count = 1;
  2296. trailing_vheap_pages_count = 1;
  2297. { void *pp = pages[--pages_count];
  2298. char *vf, *vl;
  2299. unsigned int len;
  2300. /*
  2301. * A first page of (cons-)heap
  2302. */
  2303. zero_out(pp);
  2304. new_heap_pages[new_heap_pages_count++] = pp;
  2305. heaplimit = doubleword_align_up((int32)pp);
  2306. qcar(heaplimit) = CSL_PAGE_SIZE;
  2307. vl = (char *)heaplimit;
  2308. fringe = (Lisp_Object)(vl + CSL_PAGE_SIZE);
  2309. heaplimit = (Lisp_Object)(vl + SPARE);
  2310. #ifdef DEBUG_GC
  2311. term_printf("fr = %.8lx, hl = %.8lx\n", (long)fringe, (long)heaplimit);
  2312. #endif
  2313. /*
  2314. * A first page of vector heap.
  2315. */
  2316. pp = pages[--pages_count];
  2317. zero_out(pp);
  2318. new_vheap_pages[new_vheap_pages_count++] = pp;
  2319. vf = (char *)doubleword_align_up((int32)pp) + 8;
  2320. vfringe = (Lisp_Object)vf;
  2321. vl = vf + (CSL_PAGE_SIZE - 16);
  2322. vheaplimit = (Lisp_Object)vl;
  2323. len = (unsigned int)(vf - (vl - (CSL_PAGE_SIZE - 8)));
  2324. qcar(vl - (CSL_PAGE_SIZE - 8)) = (Lisp_Object)len;
  2325. #ifdef DEBUG_GC
  2326. term_printf("vfr = %.8lx, vhl = %.8lx\n", (long)vfringe, (long)vheaplimit);
  2327. #endif
  2328. /*
  2329. * The BPS heap can start of utterly non-existent.
  2330. */
  2331. codefringe = codelimit = 0;
  2332. }
  2333. /*
  2334. * The very first thing that I will copy will be the main object-vector,
  2335. * this is done early to ensure that it gets a full empty page of vector
  2336. * heap to fit into.
  2337. */
  2338. copy(&((Lisp_Object *)nil)[current_package_offset]);
  2339. /*
  2340. * The above line is "really"
  2341. * copy(&current_package);
  2342. * but I use an offset into the nilseg in explicit for because otherwise
  2343. * there is a big foul-up with the NILSEG_EXTERNS option... Sorry!
  2344. */
  2345. /*
  2346. * I should remind you, gentle reader, that the value cell
  2347. * and env cells of nil will always contain nil, which does not move,
  2348. * and so I do not need to copy them here.
  2349. */
  2350. copy(&(qplist(nil)));
  2351. copy(&(qpname(nil)));
  2352. copy(&(qfastgets(nil)));
  2353. #ifdef COMMON
  2354. copy(&(qpackage(nil)));
  2355. #endif
  2356. /*
  2357. * I dislike the special treatment of current_package that follows. Maybe
  2358. * I should arrange something totally different for copying the package
  2359. * structure...
  2360. */
  2361. for (i = first_nil_offset; i<last_nil_offset; i++)
  2362. if (i != current_package_offset)
  2363. /* current-package - already copied by hand */
  2364. copy(&((Lisp_Object *)nil)[i]);
  2365. for (sp=stack; sp>(Lisp_Object *)stackbase; sp--) copy(sp);
  2366. /*
  2367. * Now I need to perform some magic on the list of hash tables...
  2368. */
  2369. lose_dead_hashtables();
  2370. copy(&eq_hash_tables);
  2371. copy(&equal_hash_tables);
  2372. { char *fr = (char *)fringe,
  2373. *vf = (char *)vfringe,
  2374. *cf = (char *)codefringe,
  2375. *hl = (char *)heaplimit,
  2376. *vl = (char *)vheaplimit,
  2377. *cl = (char *)codelimit;
  2378. unsigned int len = (unsigned int)(fr - (hl - SPARE));
  2379. qcar(hl - SPARE) = (Lisp_Object)len;
  2380. len = (unsigned int)(vf - (vl - (CSL_PAGE_SIZE - 8)));
  2381. qcar(vl - (CSL_PAGE_SIZE - 8)) = (Lisp_Object)len;
  2382. if (codelimit != 0)
  2383. { len = (unsigned int)(cf - (cl - 8));
  2384. qcar(cl - 8) = (Lisp_Object)len;
  2385. }
  2386. }
  2387. /*
  2388. * Throw away the old semi-space - it is now junk.
  2389. */
  2390. while (heap_pages_count!=0)
  2391. pages[pages_count++] = heap_pages[--heap_pages_count];
  2392. while (vheap_pages_count!=0)
  2393. pages[pages_count++] = vheap_pages[--vheap_pages_count];
  2394. while (bps_pages_count!=0)
  2395. pages[pages_count++] = bps_pages[--bps_pages_count];
  2396. /*
  2397. * Flip the descriptors for the old and new semi-spaces.
  2398. */
  2399. { void **w = heap_pages;
  2400. heap_pages = new_heap_pages;
  2401. new_heap_pages = w;
  2402. w = vheap_pages;
  2403. vheap_pages = new_vheap_pages;
  2404. new_vheap_pages = w;
  2405. w = bps_pages;
  2406. bps_pages = new_bps_pages;
  2407. new_bps_pages = w;
  2408. heap_pages_count = new_heap_pages_count;
  2409. new_heap_pages_count = 0;
  2410. vheap_pages_count = new_vheap_pages_count;
  2411. new_vheap_pages_count = 0;
  2412. bps_pages_count = new_bps_pages_count;
  2413. new_bps_pages_count = 0;
  2414. }
  2415. }
  2416. else
  2417. #endif /* NO_COPYING_GC */
  2418. {
  2419. /*
  2420. * The list bases to mark from are
  2421. * (a) nil [NB: mark(nil) would be ineffective],
  2422. * (b) the special ones addressed relative to nil,
  2423. * (c) everything on the Lisp stack,
  2424. * (d) the package structure,
  2425. * (e) the argument (p) passed to reclaim().
  2426. */
  2427. qheader(nil) = set_mark_bit_h(qheader(nil));
  2428. /* nil has nil as value & env ... */
  2429. mark(&qplist(nil)); /* ... thus only its plist and ... */
  2430. mark(&qpname(nil)); /* ... pname cell need marking, */
  2431. /* ... since packages are done later */
  2432. mark(&qfastgets(nil)); /* + the fastgets vector, if any */
  2433. for (i = first_nil_offset; i<last_nil_offset; i++)
  2434. {
  2435. mark(&((Lisp_Object *)nil)[i]);
  2436. #ifdef TICK_STREAM
  2437. if (tick_on_gc_exit)
  2438. {
  2439. inject_randomness((int)clock());
  2440. accept_tick();
  2441. tick_on_gc_exit = NO;
  2442. }
  2443. #endif
  2444. }
  2445. for (sp=stack; sp>(Lisp_Object *)stackbase; sp--)
  2446. {
  2447. mark(sp);
  2448. #ifdef TICK_STREAM
  2449. if (tick_on_gc_exit)
  2450. {
  2451. inject_randomness((int)clock());
  2452. accept_tick();
  2453. tick_on_gc_exit = NO;
  2454. }
  2455. #endif
  2456. }
  2457. /*
  2458. * Now I need to perform some magic on the list of hash tables...
  2459. */
  2460. lose_dead_hashtables();
  2461. mark(&eq_hash_tables);
  2462. mark(&equal_hash_tables);
  2463. /*
  2464. * What about the package structure... ? I assume it has been marked by
  2465. * what I have just done.
  2466. */
  2467. qheader(nil) = clear_mark_bit_h(qheader(nil));
  2468. t1 = read_clock();
  2469. bottom_page_number = compress_heap(); /* Folds cons cells upwards */
  2470. t2 = read_clock();
  2471. /*
  2472. * Again I should remind you, gentle reader, that the value cell
  2473. * and env cells of nil will always contain nil, which does not move,
  2474. * and so I do not need to relocate them here.
  2475. */
  2476. relocate(&(qplist(nil)));
  2477. /* relocate(&(qpname(nil))); never a cons cell */
  2478. relocate(&(qfastgets(nil)));
  2479. #ifdef COMMON
  2480. relocate(&(qpackage(nil)));
  2481. #endif
  2482. for (i = first_nil_offset; i<last_nil_offset; i++)
  2483. relocate(&((Lisp_Object *)nil)[i]);
  2484. for (sp=stack; sp>(Lisp_Object *)stackbase; sp--) relocate(sp);
  2485. relocate_consheap(bottom_page_number);
  2486. relocate(&eq_hash_tables);
  2487. relocate(&equal_hash_tables);
  2488. relocate_vecheap();
  2489. { char *fr = (char *)fringe,
  2490. *vf = (char *)vfringe,
  2491. *cf = (char *)codefringe,
  2492. *hl = (char *)heaplimit,
  2493. *vl = (char *)vheaplimit,
  2494. *cl = (char *)codelimit;
  2495. unsigned int len = (unsigned int)(fr - (hl - SPARE));
  2496. qcar(hl - SPARE) = (Lisp_Object)len;
  2497. len = (unsigned int)(vf - (vl - (CSL_PAGE_SIZE - 8)));
  2498. qcar(vl - (CSL_PAGE_SIZE - 8)) = (Lisp_Object)len;
  2499. if (codelimit != 0)
  2500. { len = (unsigned int)(cf - (cl - 8));
  2501. qcar(cl - 8) = (Lisp_Object)len;
  2502. }
  2503. }
  2504. abandon_heap_pages(bottom_page_number);
  2505. }
  2506. { Lisp_Object qq;
  2507. /*
  2508. * Note that EQUAL hash tables do not need to be rehashed here, though
  2509. * they do if a heap image is exported from one system to another.
  2510. */
  2511. for (qq = eq_hash_tables; qq!=nil; qq=qcdr(qq))
  2512. rehash_this_table(qcar(qq));
  2513. }
  2514. gc_time += pop_clock();
  2515. t3 = base_time;
  2516. copy_out_of_nilseg(NO);
  2517. if ((verbos_flag & 5) == 5)
  2518. /*
  2519. * (verbos 4) gets the system to tell me how long each phase of GC took,
  2520. * but (verbos 1) must be ORd in too.
  2521. */
  2522. {
  2523. #ifndef NO_COPYING_GC
  2524. if (gc_method)
  2525. trace_printf("Copy %ld ms\n",
  2526. (long int)(1000.0 * (double)(t3-t0)/(double)CLOCKS_PER_SEC));
  2527. else
  2528. #endif
  2529. trace_printf("Mark %ld, compact %ld, relocate %ld ms\n",
  2530. (long int)(1000.0 * (double)(t1-t0)/(double)CLOCKS_PER_SEC),
  2531. (long int)(1000.0 * (double)(t2-t1)/(double)CLOCKS_PER_SEC),
  2532. (long int)(1000.0 * (double)(t3-t2)/(double)CLOCKS_PER_SEC));
  2533. }
  2534. /* (verbos 5) causes a display breaking down how space is used */
  2535. if ((verbos_flag & 5) == 5)
  2536. { trace_printf(
  2537. "cons_cells=%d, symbol_heads=%d, strings=%d, user_vectors=%d\n",
  2538. cons_cells, symbol_heads, strings, user_vectors-litvecs-getvecs);
  2539. trace_printf(
  2540. "bignums=%d, floats=%d, bytestreams=%d, other=%d, litvecs=%d\n",
  2541. big_numbers, box_floats, bytestreams, other_mem, litvecs);
  2542. trace_printf("getvecs=%d\n", getvecs);
  2543. }
  2544. pop(p);
  2545. if (!reset_limit_registers(vheap_need, bps_need, native_need))
  2546. { term_printf("\n+++ No space left at all\n");
  2547. my_exit(EXIT_FAILURE); /* totally drastic... */
  2548. }
  2549. #ifndef HOLD_BACK_MEMORY
  2550. #ifndef MEMORY_TRACE
  2551. /*
  2552. * Here I grab more memory (if I am allowed to).
  2553. * An initial version here, and one still suitable on machines that will
  2554. * have plenty of real memory, will be to defined ok_to_grab_memory(n) as
  2555. * 3*n + 2. This expands until the proportion of the heap active at the
  2556. * end of garbage collection is less than 1/4.
  2557. * If the attempt to grab more memory fails I clear the bit in init_flags
  2558. * that allows me to try to expand, so I will not waste time again. If
  2559. * HOLD_BACK_MEMORY was asserted (for machines where grabbing all seemingly
  2560. * available memory may cause a crash) I do not try this operation. The
  2561. * aim of keeping the heap less than half full is an heuristic and could be
  2562. * adjusted on the basis of experience with this code.
  2563. * The "+2" at the end of calculating the ideal heap size is intended
  2564. * to keep us (mostly) in the copying GC domain. If it is omitted the
  2565. * heap tends to stay just 25% full and sliding GC is used. Overall this is
  2566. * roughly as expensive as copying, but it is more disruptive since it comes
  2567. * in larger gulps.
  2568. * On systems where it is possible to measure the amount of available
  2569. * real memory more sophisticated calculations may be possible.
  2570. */
  2571. if (init_flags & INIT_EXPANDABLE)
  2572. { int32 ideal = ok_to_grab_memory(heap_pages_count +
  2573. vheap_pages_count +
  2574. bps_pages_count);
  2575. int32 more;
  2576. if (ideal > MAX_PAGES) ideal = MAX_PAGES;
  2577. more = ideal - pages_count;
  2578. while (more-- > 0)
  2579. { void *page = (void *)my_malloc((size_t)(CSL_PAGE_SIZE + 8));
  2580. int32 pun, pun1;
  2581. /*
  2582. * When I first grabbed memory in restart.c I used my_malloc_1(), which
  2583. * gobbles a large stack frame and then called regular malloc - the idea
  2584. * there was to avoid malloc grabbing space needed for the stack. I can
  2585. * not properly do that here since reclaim() may be called with a deep
  2586. * stack already active. There is thus a danger that expanding the heap here
  2587. * may cause me to run out of stack elsewhere. Oh well, I guess I can not
  2588. * win in all ways.
  2589. */
  2590. /*
  2591. * Verify that new block does not span zero & has correct sign bit
  2592. */
  2593. pun = (int32)page;
  2594. pun1 = (int32)((char *)page + CSL_PAGE_SIZE + 8);
  2595. if ((pun ^ pun1) < 0) page = NULL;
  2596. #ifdef ADDRESS_SIGN_UNKNOWN
  2597. if ((pun + address_sign) < 0) page = NULL;
  2598. #else
  2599. #ifdef ADDRESSES_HAVE_TOP_BIT_SET
  2600. if (pun > 0) page = NULL;
  2601. #else
  2602. if (pun < 0) page = NULL;
  2603. #endif
  2604. #endif
  2605. if (page == NULL)
  2606. { init_flags &= ~INIT_EXPANDABLE;
  2607. break;
  2608. }
  2609. else pages[pages_count++] = page;
  2610. }
  2611. }
  2612. #endif /* MEMORY_TRACE */
  2613. #endif /* HOLD_BACK_MEMORY */
  2614. #ifdef WINDOW_SYSTEM
  2615. { int32 n = heap_pages_count + vheap_pages_count + bps_pages_count;
  2616. int32 n1 = n + pages_count;
  2617. double z = (100.0*n)/n1;
  2618. report_space(gc_number, z);
  2619. if (verbos_flag & 1) trace_printf(
  2620. "At gc end about %.1f Mbytes of %.1f (%.1f%%) of heap is in use\n",
  2621. ((double)n)*(CSL_PAGE_SIZE/(1024.0*1024.0)),
  2622. ((double)n1)*(CSL_PAGE_SIZE/(1024.0*1024.0)), z);
  2623. }
  2624. #else
  2625. if (verbos_flag & 1)
  2626. { int32 n = heap_pages_count + vheap_pages_count + bps_pages_count;
  2627. int32 n1 = n + pages_count;
  2628. trace_printf(
  2629. "At gc end about %.1f Mbytes of %.1f (%.1f%%) of heap is in use\n",
  2630. (double)n*(CSL_PAGE_SIZE/(1024.0*1024.0)),
  2631. (double)n1*(CSL_PAGE_SIZE/(1024.0*1024.0)),
  2632. (100.0*n)/n1);
  2633. }
  2634. #endif
  2635. #ifndef NO_COPYING_GC
  2636. /*
  2637. * I will make the next garbage collection a copying one if the heap is
  2638. * at most 25% full, or a sliding one if it is more full than that.
  2639. */
  2640. gc_method = (pages_count >
  2641. 3*(heap_pages_count + vheap_pages_count + bps_pages_count));
  2642. #endif
  2643. if (stop_after_gc)
  2644. {
  2645. #ifdef MEMORY_TRACE
  2646. memory_comment(15);
  2647. #endif
  2648. return Lstop(nil, fixnum_of_int(0));
  2649. }
  2650. #ifdef POLL_FOR_ATTN
  2651. poll_for_attn(); /* Should cause ctrl-C checking */
  2652. nil = C_nil;
  2653. if (exception_pending())
  2654. {
  2655. #ifdef MEMORY_TRACE
  2656. memory_comment(15);
  2657. #endif
  2658. return nil;
  2659. }
  2660. #endif
  2661. #ifdef MEMORY_TRACE
  2662. memory_comment(15);
  2663. #endif
  2664. if (interrupt_pending)
  2665. { interrupt_pending = NO;
  2666. already_in_gc = NO;
  2667. tick_on_gc_exit = NO;
  2668. return interrupted(p);
  2669. }
  2670. already_in_gc = NO;
  2671. if (tick_on_gc_exit)
  2672. {
  2673. inject_randomness((int)clock());
  2674. accept_tick();
  2675. nil = C_nil;
  2676. if (exception_pending()) return nil;
  2677. tick_on_gc_exit = NO;
  2678. return onevalue(p);
  2679. }
  2680. return onevalue(p);
  2681. #endif /* DEMO_MODE */
  2682. }
  2683. /* end of file gc.c */