PageRenderTime 79ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/kits/scc/heap.c

http://github.com/pablomarx/Thomas
C | 1835 lines | 1371 code | 213 blank | 251 comment | 334 complexity | 4a8cc2f49167b71be0df36e98f7cafaf MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /* SCHEME->C */
  2. /* Copyright 1989 Digital Equipment Corporation
  3. * All Rights Reserved
  4. *
  5. * Permission to use, copy, and modify this software and its documentation is
  6. * hereby granted only under the following terms and conditions. Both the
  7. * above copyright notice and this permission notice must appear in all copies
  8. * of the software, derivative works or modified versions, and any portions
  9. * thereof, and both notices must appear in supporting documentation.
  10. *
  11. * Users of this software agree to the terms and conditions set forth herein,
  12. * and hereby grant back to Digital a non-exclusive, unrestricted, royalty-free
  13. * right and license under any changes, enhancements or extensions made to the
  14. * core functions of the software, including but not limited to those affording
  15. * compatibility with other hardware or software environments, but excluding
  16. * applications which incorporate this software. Users further agree to use
  17. * their best efforts to return to Digital any such changes, enhancements or
  18. * extensions that they make and inform Digital of noteworthy uses of this
  19. * software. Correspondence should be provided to Digital at:
  20. *
  21. * Director of Licensing
  22. * Western Research Laboratory
  23. * Digital Equipment Corporation
  24. * 250 University Avenue
  25. * Palo Alto, California 94301
  26. *
  27. * This software may be distributed (but not offered for sale or transferred
  28. * for compensation) to third parties, provided such third parties agree to
  29. * abide by the terms and conditions of this notice.
  30. *
  31. * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
  32. * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
  33. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
  34. * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  35. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  36. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  37. * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  38. * SOFTWARE.
  39. */
  40. /* This module implements the object storage storage system. */
  41. /* Import definitions */
  42. #include "objects.h"
  43. #include "scinit.h"
  44. #include "heap.h"
  45. #include "callcc.h"
  46. #include "signal.h"
  47. #include "apply.h"
  48. extern abort();
  49. #ifdef MIPS
  50. extern sc_s0tos8();
  51. #endif
  52. #ifdef VAX
  53. extern sc_r2tor11();
  54. #endif
  55. /* Forward declarations */
  56. static int move_ptr();
  57. static SCP move_object();
  58. static void move_continuation_ptr();
  59. /* Allocate storage which is defined in "heap.h" */
  60. int *sc_pagegeneration, /* page generation table */
  61. *sc_pagetype, /* page type table */
  62. *sc_pagelock, /* page lock table */
  63. *sc_pagelink, /* page lock list link table */
  64. sc_initiallink, /* Value to put in sc_pagelink field for a
  65. newly allocated page */
  66. sc_locklist, /* list header for locked pages */
  67. sc_genlist, /* list of modified pages */
  68. sc_lockcnt, /* # of locked pages */
  69. sc_current_generation, /* current generation */
  70. sc_next_generation; /* next generation */
  71. int sc_firstheappage, /* first page in the Scheme heap */
  72. sc_lastheappage, /* last page in the Scheme heap */
  73. sc_limit, /* % of heap allocated after collecton
  74. that forces total collection */
  75. sc_freepage, /* free page index */
  76. sc_heappages, /* # of pages in the Scheme heap */
  77. sc_maxheappages, /* Maximum # of pages in Scheme heap */
  78. sc_allocatedheappages, /* # of pages currently allocated */
  79. sc_generationpages, /* # of pages in saved generations */
  80. *sc_firstheapp, /* ptr to first word in the Scheme heap */
  81. *sc_lastheapp; /* ptr to last word in the Scheme heap */
  82. int sc_conscnt; /* # cons cells in sc_consp */
  83. SCP sc_consp; /* pointer to next cons cell */
  84. int sc_extobjwords, /* # of words for ext objs in sc_extobjp */
  85. sc_extwaste; /* # of words wasted on page crossings */
  86. SCP sc_extobjp; /* pointer to next free extended obj word */
  87. int sc_gcinfo; /* controls logging */
  88. static struct rusage gcru, /* resource consumption during collection */
  89. startru,
  90. stopru;
  91. static int sc_newlist; /* list of newly allocated pages */
  92. int *sc_stackbase; /* pointer to base of the stack */
  93. TSCP sc_whenfreed, /* list of items needing cleanup when free */
  94. sc_freed; /* list of free items to be cleanup */
  95. TSCP sc_after_2dcollect_v, /* Collection status callback */
  96. sc__2afrozen_2dobjects_2a_v;
  97. /* User managed frozen object list */
  98. /* Each time a weak-cons is created, an entry is made on the following list.
  99. Each entry of the list is a 3-element vector with the following fields:
  100. pointer to the next entry (or EMPTYLIST)
  101. pointer to the cons cell
  102. cell to hold the original value from the CAR of the cons cell
  103. */
  104. static TSCP weakconsl = EMPTYLIST;
  105. #define WEAK_LINK( x ) VECTOR_ELEMENT( x, C_FIXED( 0 ) )
  106. #define WEAK_CONS( x ) VECTOR_ELEMENT( x, C_FIXED( 1 ) )
  107. #define WEAK_CAR( x ) VECTOR_ELEMENT( x, C_FIXED( 2 ) )
  108. #define MAKE_WEAK sc_make_2dvector( C_FIXED( 3 ), EMPTYLIST )
  109. /* When pages are allocated during garbage collection, they are queued on the
  110. following two lists for later scanning. One list holds pages allocated for
  111. cons cells and the other holds pages allocated for extended objects. The
  112. lists are threaded through sc_pagelink, the pointer points to the tail of
  113. the list, and the tail link points to the head.
  114. */
  115. static int cons_pages = 0,
  116. extended_pages = 0;
  117. #define QUEUE_PAGE( tail, page ) \
  118. if (tail == 0) { \
  119. tail = sc_pagelink[ page ] = page; \
  120. } else { \
  121. sc_pagelink[ page ] = sc_pagelink[ tail ]; \
  122. sc_pagelink[ tail ] = page; \
  123. tail = page; \
  124. }
  125. #define DELETE_PAGE( tail, page ) \
  126. if (tail == 0) \
  127. page = NULL; \
  128. else { \
  129. page = sc_pagelink[ tail ]; \
  130. sc_pagelink[ tail ] = sc_pagelink[ page ]; \
  131. if (tail == page) tail = 0; \
  132. }
  133. /* The following function converts a rusage structure into an 18 word Scheme
  134. vector composed of the same items.
  135. */
  136. static TSCP rusagevector( ru )
  137. struct rusage *ru;
  138. {
  139. TSCP v;
  140. PATSCP ve;
  141. v = sc_make_2dvector( C_FIXED( 18 ), EMPTYLIST );
  142. ve = &(T_U( v )->vector.element0);
  143. *ve++ = C_FIXED( ru->ru_utime.tv_sec );
  144. *ve++ = C_FIXED( ru->ru_utime.tv_usec );
  145. *ve++ = C_FIXED( ru->ru_stime.tv_sec );
  146. *ve++ = C_FIXED( ru->ru_stime.tv_usec );
  147. *ve++ = C_FIXED( ru->ru_maxrss );
  148. *ve++ = C_FIXED( ru->ru_ixrss );
  149. *ve++ = C_FIXED( ru->ru_idrss );
  150. *ve++ = C_FIXED( ru->ru_isrss );
  151. *ve++ = C_FIXED( ru->ru_minflt );
  152. *ve++ = C_FIXED( ru->ru_majflt );
  153. *ve++ = C_FIXED( ru->ru_nswap );
  154. *ve++ = C_FIXED( ru->ru_inblock );
  155. *ve++ = C_FIXED( ru->ru_oublock );
  156. *ve++ = C_FIXED( ru->ru_msgsnd );
  157. *ve++ = C_FIXED( ru->ru_msgrcv );
  158. *ve++ = C_FIXED( ru->ru_nsignals );
  159. *ve++ = C_FIXED( ru->ru_nvcsw );
  160. *ve++ = C_FIXED( ru->ru_nivcsw );
  161. return( v );
  162. }
  163. /* Garbage collector resource usage is accumulated by the following function.
  164. It will accumlate the resources used in gcru, and change stopru to reflect
  165. the resource usage this collection.
  166. */
  167. static updategcru()
  168. {
  169. int x;
  170. /* Compute deltas in stopru */
  171. if (stopru.ru_utime.tv_usec < startru.ru_utime.tv_usec) {
  172. stopru.ru_utime.tv_sec = stopru.ru_utime.tv_sec-
  173. startru.ru_utime.tv_sec-1;
  174. stopru.ru_utime.tv_usec = 1000000+stopru.ru_utime.tv_usec-
  175. startru.ru_utime.tv_usec;
  176. }
  177. else {
  178. stopru.ru_utime.tv_sec = stopru.ru_utime.tv_sec-
  179. startru.ru_utime.tv_sec;
  180. stopru.ru_utime.tv_usec = stopru.ru_utime.tv_usec-
  181. startru.ru_utime.tv_usec;
  182. }
  183. if (stopru.ru_stime.tv_usec < startru.ru_stime.tv_usec) {
  184. stopru.ru_stime.tv_sec = stopru.ru_stime.tv_sec-
  185. startru.ru_stime.tv_sec-1;
  186. stopru.ru_stime.tv_usec = 1000000+stopru.ru_stime.tv_usec-
  187. startru.ru_stime.tv_usec;
  188. }
  189. else {
  190. stopru.ru_stime.tv_sec = stopru.ru_stime.tv_sec-
  191. startru.ru_stime.tv_sec;
  192. stopru.ru_stime.tv_usec = stopru.ru_stime.tv_usec-
  193. startru.ru_stime.tv_usec;
  194. }
  195. stopru.ru_minflt -= startru.ru_minflt;
  196. stopru.ru_majflt -= startru.ru_majflt;
  197. stopru.ru_nswap -= startru.ru_nswap;
  198. stopru.ru_inblock -= startru.ru_inblock;
  199. stopru.ru_oublock -= startru.ru_oublock;
  200. stopru.ru_msgsnd -= startru.ru_msgsnd;
  201. stopru.ru_msgrcv -= startru.ru_msgrcv;
  202. stopru.ru_nsignals -= startru.ru_nsignals;
  203. stopru.ru_nvcsw -= startru.ru_nvcsw;
  204. stopru.ru_nivcsw -= startru.ru_nivcsw;
  205. /* Accumulate totals in gcru */
  206. x = gcru.ru_utime.tv_usec+stopru.ru_utime.tv_usec;
  207. gcru.ru_utime.tv_usec = x % 1000000;
  208. gcru.ru_utime.tv_sec = gcru.ru_utime.tv_sec+stopru.ru_utime.tv_sec+
  209. x / 1000000;
  210. x = gcru.ru_stime.tv_usec+stopru.ru_stime.tv_usec;
  211. gcru.ru_stime.tv_usec = x % 1000000;
  212. gcru.ru_stime.tv_sec = gcru.ru_stime.tv_sec+stopru.ru_stime.tv_sec+
  213. x / 1000000;
  214. gcru.ru_maxrss = stopru.ru_maxrss;
  215. gcru.ru_ixrss = stopru.ru_ixrss;
  216. gcru.ru_idrss = stopru.ru_idrss;
  217. gcru.ru_minflt += stopru.ru_minflt;
  218. gcru.ru_majflt += stopru.ru_majflt;
  219. gcru.ru_nswap += stopru.ru_nswap;
  220. gcru.ru_inblock += stopru.ru_inblock;
  221. gcru.ru_oublock += stopru.ru_oublock;
  222. gcru.ru_msgsnd += stopru.ru_msgsnd;
  223. gcru.ru_msgrcv += stopru.ru_msgrcv;
  224. gcru.ru_nsignals += stopru.ru_nsignals;
  225. gcru.ru_nvcsw += stopru.ru_nvcsw;
  226. gcru.ru_nivcsw += stopru.ru_nivcsw;
  227. }
  228. /* The following function returns the resource usage information for the
  229. process. It returns a vector formed of the elements in the rusage struct
  230. returned by getrusage. It is visible in Scheme as (MY-RUSAGE).
  231. */
  232. TSCP sc_my_2drusage_v;
  233. TSCP sc_my_2drusage()
  234. {
  235. struct rusage ru;
  236. getrusage( 0, &ru );
  237. return( rusagevector( &ru ) );
  238. }
  239. /* The following function returns the resource usage information for the
  240. garbage collector. It returns a vector formed of the elements in the rusage
  241. struct maintained by the collector. It is visible in Scheme as
  242. (COLLECT-RUSAGE).
  243. */
  244. TSCP sc_collect_2drusage_v;
  245. TSCP sc_collect_2drusage()
  246. {
  247. return( rusagevector( &gcru ) );
  248. }
  249. /* Errors detected during garbage collection are logged by the following
  250. procedure. If any errors occur, the program will abort after logging
  251. them. More than 30 errors will result in the program being aborted at
  252. once.
  253. */
  254. static SCP moving_object;
  255. static int pointer_errors = 0;
  256. static void pointererror( msg, pp )
  257. char* msg;
  258. SCP pp;
  259. {
  260. fprintf( stderr, "***** COLLECT pointer error in %x, ",
  261. moving_object );
  262. fprintf( stderr, msg, pp );
  263. if (++pointer_errors == 30) abort();
  264. }
  265. #ifdef TITAN
  266. /* The following function is called to read one of the Titan registers. It
  267. must be open-coded using constant register numbers as zzReadRegister is
  268. actually a Mahler inline function which expects a constant register
  269. number.
  270. */
  271. int *sc_processor_register( regnum )
  272. {
  273. switch (regnum) {
  274. case 0: return( zzReadRegister( 0 ) );
  275. case 1: return( zzReadRegister( 1 ) );
  276. case 2: return( zzReadRegister( 2 ) );
  277. case 3: return( zzReadRegister( 3 ) );
  278. case 4: return( zzReadRegister( 4 ) );
  279. case 5: return( zzReadRegister( 5 ) );
  280. case 6: return( zzReadRegister( 6 ) );
  281. case 7: return( zzReadRegister( 7 ) );
  282. case 8: return( zzReadRegister( 8 ) );
  283. case 9: return( zzReadRegister( 9 ) );
  284. case 10: return( zzReadRegister( 10 ) );
  285. case 11: return( zzReadRegister( 11 ) );
  286. case 12: return( zzReadRegister( 12 ) );
  287. case 13: return( zzReadRegister( 13 ) );
  288. case 14: return( zzReadRegister( 14 ) );
  289. case 15: return( zzReadRegister( 15 ) );
  290. case 16: return( zzReadRegister( 16 ) );
  291. case 17: return( zzReadRegister( 17 ) );
  292. case 18: return( zzReadRegister( 18 ) );
  293. case 19: return( zzReadRegister( 19 ) );
  294. case 20: return( zzReadRegister( 20 ) );
  295. case 21: return( zzReadRegister( 21 ) );
  296. case 22: return( zzReadRegister( 22 ) );
  297. case 23: return( zzReadRegister( 23 ) );
  298. case 24: return( zzReadRegister( 24 ) );
  299. case 25: return( zzReadRegister( 25 ) );
  300. case 26: return( zzReadRegister( 26 ) );
  301. case 27: return( zzReadRegister( 27 ) );
  302. case 28: return( zzReadRegister( 28 ) );
  303. case 29: return( zzReadRegister( 29 ) );
  304. case 30: return( zzReadRegister( 30 ) );
  305. case 31: return( zzReadRegister( 31 ) );
  306. case 32: return( zzReadRegister( 32 ) );
  307. case 33: return( zzReadRegister( 33 ) );
  308. case 34: return( zzReadRegister( 34 ) );
  309. case 35: return( zzReadRegister( 35 ) );
  310. case 36: return( zzReadRegister( 36 ) );
  311. case 37: return( zzReadRegister( 37 ) );
  312. case 38: return( zzReadRegister( 38 ) );
  313. case 39: return( zzReadRegister( 39 ) );
  314. case 40: return( zzReadRegister( 40 ) );
  315. case 41: return( zzReadRegister( 41 ) );
  316. case 42: return( zzReadRegister( 42 ) );
  317. case 43: return( zzReadRegister( 43 ) );
  318. case 44: return( zzReadRegister( 44 ) );
  319. case 45: return( zzReadRegister( 45 ) );
  320. case 46: return( zzReadRegister( 46 ) );
  321. case 47: return( zzReadRegister( 47 ) );
  322. case 48: return( zzReadRegister( 48 ) );
  323. case 49: return( zzReadRegister( 49 ) );
  324. case 50: return( zzReadRegister( 50 ) );
  325. case 51: return( zzReadRegister( 51 ) );
  326. case 52: return( zzReadRegister( 52 ) );
  327. case 53: return( zzReadRegister( 53 ) );
  328. case 54: return( zzReadRegister( 54 ) );
  329. case 55: return( zzReadRegister( 55 ) );
  330. case 56: return( zzReadRegister( 56 ) );
  331. case 57: return( zzReadRegister( 57 ) );
  332. case 58: return( zzReadRegister( 58 ) );
  333. case 59: return( zzReadRegister( 59 ) );
  334. case 60: return( zzReadRegister( 60 ) );
  335. case 61: return( zzReadRegister( 61 ) );
  336. case 62: return( zzReadRegister( 62 ) );
  337. case 63: return( zzReadRegister( 63 ) );
  338. default: return( 0 );
  339. }
  340. }
  341. /* All processor registers are traced by the following procedure. */
  342. static trace_stack_and_registers()
  343. {
  344. int i, *r0tor60[ 61 ], *pp;
  345. for (i = 0; i <= 60; i++) r0tor60[ i ] = sc_processor_register( i );
  346. pp = STACKPTR;
  347. while (pp != sc_stackbase) move_continuation_ptr( *pp++ );
  348. }
  349. #endif
  350. #ifdef VAX
  351. /* The following code is used to read the stack pointer. The register
  352. number is passed in to force an argument to be on the stack, which in
  353. turn can be used to find the address of the top of stack.
  354. */
  355. int *sc_processor_register( reg )
  356. int reg;
  357. {
  358. return( &reg+1 );
  359. }
  360. /* All processor registers which might contain pointers are traced by the
  361. following procedure.
  362. */
  363. static trace_stack_and_registers()
  364. {
  365. int i, r2tor11[10], *pp;
  366. sc_r2tor11( r2tor11 );
  367. pp = STACKPTR;
  368. while (pp != sc_stackbase) move_continuation_ptr( *pp++ );
  369. }
  370. #endif
  371. #ifdef MIPS
  372. /* The following code is used to read the stack pointer. The register
  373. number is passed in to force an argument to be on the stack, which in
  374. turn can be used to find the address of the top of stack.
  375. */
  376. int *sc_processor_register( reg )
  377. int reg;
  378. {
  379. return( &reg );
  380. }
  381. /* All processor registers which might contain pointers are traced by the
  382. following procedure.
  383. */
  384. static trace_stack_and_registers()
  385. {
  386. int i, s0tos8[9], *pp;
  387. sc_s0tos8( s0tos8 );
  388. pp = STACKPTR;
  389. while (pp != sc_stackbase) move_continuation_ptr( *pp++ );
  390. }
  391. #endif
  392. /* The size of an extended object in words is returned by the following
  393. function.
  394. */
  395. static int extendedsize( obj )
  396. SCP obj;
  397. {
  398. switch (obj->extendedobj.tag) {
  399. case SYMBOLTAG:
  400. return( SYMBOLSIZE );
  401. case STRINGTAG:
  402. return( STRINGSIZE( obj->string.length ) );
  403. case VECTORTAG:
  404. return( VECTORSIZE( obj->vector.length ) );
  405. case PROCEDURETAG:
  406. return( PROCEDURESIZE );
  407. case CLOSURETAG:
  408. return( CLOSURESIZE( obj->closure.length ) );
  409. case CONTINUATIONTAG:
  410. return( CONTINUATIONSIZE( obj->continuation.length ) );
  411. case FLOAT32TAG:
  412. return( FLOAT32SIZE );
  413. case FLOAT64TAG:
  414. return( FLOAT64SIZE );
  415. case FORWARDTAG:
  416. return( FORWARDSIZE( obj->forward.length ) );
  417. case WORDALIGNTAG:
  418. return( WORDALIGNSIZE );
  419. default:
  420. fprintf( stderr,
  421. "***** COLLECT Unknown extended object: %x %x\n",
  422. obj, obj->extendedobj.tag );
  423. abort();
  424. }
  425. }
  426. /* Words inside continuations are checked by the following function. If the
  427. word looks like a pointer, then the page containing the object will be
  428. locked and the object will be moved.
  429. */
  430. static void move_continuation_ptr( pp )
  431. SCP pp;
  432. {
  433. int page, tag;
  434. SCP sweep, next;
  435. if (pp >= (SCP)sc_firstheapp && pp < (SCP)sc_lastheapp) {
  436. page = ADDRESS_PAGE( pp );
  437. if (sc_current_generation == sc_pagegeneration[ page ]) {
  438. tag = sc_pagetype[ page ];
  439. if (tag == PAIRTAG) {
  440. /* Trace just that PAIR */
  441. pp = (SCP)(((int)pp) & ~(CONSBYTES-1));
  442. if (sc_pagelock[ page ] == 0) {
  443. sc_pagelock[ page ] = 1;
  444. sc_pagelink[ page ] = sc_locklist;
  445. sc_locklist = page;
  446. sc_lockcnt = sc_lockcnt+1;
  447. }
  448. if (sc_gcinfo == 2 && pp->forward.tag != FORWARDTAG)
  449. fprintf( stderr,
  450. " move_continuation_ptr %x\n",
  451. U_T( pp, PAIRTAG ) );
  452. move_ptr( U_T( pp, PAIRTAG ) );
  453. return;
  454. }
  455. /* Trace the referenced object */
  456. if (tag == BIGEXTENDEDTAG) {
  457. while (sc_pagetype[ page ] != EXTENDEDTAG) page--;
  458. }
  459. sweep = (SCP)PAGE_ADDRESS( page );
  460. if (sc_pagelock[ page ] == 0) {
  461. sc_pagelock[ page ] = 1;
  462. sc_pagelink[ page ] = sc_locklist;
  463. sc_locklist = page;
  464. if (sweep->wordalign.tag == WORDALIGNTAG) {
  465. sweep = (SCP)( ((int*)sweep)+WORDALIGNSIZE );
  466. }
  467. sc_lockcnt = (extendedsize( sweep )+PAGEWORDS-1)/PAGEWORDS+
  468. sc_lockcnt;
  469. }
  470. while (ADDRESS_PAGE( sweep ) == page &&
  471. sweep->unsi.gned != ENDOFPAGE) {
  472. next = (SCP)( ((int*)sweep)+extendedsize( sweep ) );
  473. if ((unsigned)pp < (unsigned)next) {
  474. /* sweep points to object to move */
  475. if (sc_gcinfo == 2 && sweep->forward.tag != FORWARDTAG)
  476. fprintf( stderr,
  477. " move_continuation_ptr %x\n",
  478. U_TX( sweep ) );
  479. move_ptr( U_TX( sweep ) );
  480. return;
  481. }
  482. sweep = next;
  483. }
  484. }
  485. }
  486. }
  487. /* Objects are moved from old space to new space by calling this procedure
  488. with a Scheme pointer to the object. Note that this function does not
  489. return the new value of the pointer, as it cannot be discerned at this time
  490. as all locked pages may not have been found yet. N.B. in the generational
  491. scheme, only objects in sc_current_generation are moved.
  492. */
  493. static move_ptr( tpp )
  494. TSCP tpp;
  495. {
  496. int length, words, *oldp, *newp, page;
  497. TSCP new;
  498. SCP pp;
  499. pp = T_U( tpp );
  500. switch TSCPTAG( tpp ) {
  501. case FIXNUMTAG:
  502. return;
  503. case EXTENDEDTAG:
  504. page = ADDRESS_PAGE( pp );
  505. if (NOT_S2CPAGE( page ) ||
  506. pp->forward.tag == FORWARDTAG ||
  507. pp->wordalign.tag == WORDALIGNTAG ||
  508. sc_pagegeneration[ page ] != sc_current_generation)
  509. return;
  510. if (sc_pagetype[ page ] != EXTENDEDTAG) {
  511. pointererror( "%x not in an EXTENDEDTAG page\n", pp );
  512. return;
  513. }
  514. words = extendedsize( pp );
  515. length = words;
  516. newp = (int*)sc_allocateheap( extendedsize( pp ),
  517. pp->extendedobj.tag, 0 );
  518. new = U_T( newp, EXTENDEDTAG );
  519. oldp = (int*)pp;
  520. while (words--) *newp++ = *oldp++;
  521. pp->forward.tag = FORWARDTAG;
  522. pp->forward.length = length;
  523. pp->forward.forward = new;
  524. return;
  525. case IMMEDIATETAG:
  526. return;
  527. case PAIRTAG:
  528. page = ADDRESS_PAGE( pp );
  529. if (pp->forward.tag == FORWARDTAG ||
  530. sc_pagegeneration[ page ] != sc_current_generation)
  531. return;
  532. if (sc_pagetype[ page ] != PAIRTAG) {
  533. pointererror( "%x not in a PAIRTAG page\n", pp );
  534. return;
  535. }
  536. pp->forward.forward = sc_cons( pp->pair.car, pp->pair.cdr );
  537. pp->forward.tag = FORWARDTAG;
  538. pp->forward.length = CONSSIZE;
  539. return;
  540. }
  541. }
  542. /* MOVE_OBJECT is called to move all extended objects in a page starting at
  543. a starting point. It will return a pointer to the first object that it
  544. could not move, or NULL if the page was finished.
  545. */
  546. static SCP move_object( pp )
  547. SCP pp;
  548. {
  549. int page, size, cnt, vpage;
  550. PATSCP obj;
  551. page = ADDRESS_PAGE( pp );
  552. while (ADDRESS_PAGE( pp ) == page &&
  553. (pp != sc_extobjp || sc_extobjwords == 0) &&
  554. pp->unsi.gned != ENDOFPAGE) {
  555. moving_object = pp;
  556. switch ( pp->extendedobj.tag ) {
  557. case SYMBOLTAG:
  558. move_ptr( pp->symbol.name );
  559. vpage = ADDRESS_PAGE( pp->symbol.ptrtovalue );
  560. if (S2CPAGE( vpage ))
  561. pp->symbol.ptrtovalue = &pp->symbol.value;
  562. move_ptr( *pp->symbol.ptrtovalue );
  563. move_ptr( pp->symbol.propertylist );
  564. size = SYMBOLSIZE;
  565. break;
  566. case STRINGTAG:
  567. size = STRINGSIZE( pp->string.length );
  568. break;
  569. case VECTORTAG:
  570. cnt = pp->vector.length;
  571. obj = &pp->vector.element0;
  572. while (cnt--) move_ptr( *obj++ );
  573. size = VECTORSIZE( pp->vector.length );
  574. break;
  575. case PROCEDURETAG:
  576. move_ptr( pp->procedure.closure );
  577. size = PROCEDURESIZE;
  578. break;
  579. case CLOSURETAG:
  580. move_ptr( pp->closure.closure );
  581. cnt = pp->closure.length;
  582. obj = &pp->closure.var0;
  583. while (cnt--) move_ptr( *obj++ );
  584. size = CLOSURESIZE( pp->closure.length );
  585. break;
  586. case CONTINUATIONTAG:
  587. move_ptr( pp->continuation.continuation );
  588. obj = &pp->continuation.continuation;
  589. cnt = pp->continuation.length;
  590. while (cnt--) move_continuation_ptr( *(++obj) );
  591. size = CONTINUATIONSIZE( pp->continuation.length );
  592. break;
  593. case FLOAT32TAG:
  594. size = FLOAT32SIZE;
  595. break;
  596. case FLOAT64TAG:
  597. size = FLOAT64SIZE;
  598. break;
  599. case FORWARDTAG:
  600. size = FORWARDSIZE( pp->forward.length );
  601. break;
  602. case WORDALIGNTAG:
  603. size = WORDALIGNSIZE;
  604. break;
  605. default:
  606. pointererror( "%x is not a valid extended object tag\n",
  607. pp->extendedobj.tag );
  608. }
  609. pp = (SCP)( ((int*)pp)+size );
  610. }
  611. if (ADDRESS_PAGE( pp ) == page && pp == sc_extobjp &&
  612. sc_extobjwords != 0)
  613. return( pp );
  614. return( NULL );
  615. }
  616. /* The following function is called to resolve a pointer that might be
  617. forwarded. It returns the resolved pointer.
  618. */
  619. static TSCP resolveptr( obj )
  620. TSCP obj;
  621. {
  622. if ((TSCPTAG( obj ) & 1) && (T_U( obj )->forward.tag == FORWARDTAG))
  623. return( T_U( obj )->forward.forward );
  624. return( obj );
  625. }
  626. /* Save the car of each weak cons cell that contains a pointer into the heap
  627. and replace it with #F.
  628. */
  629. static save_weakconsl()
  630. {
  631. TSCP wl, weakcons;
  632. SCP pp;
  633. wl = weakconsl;
  634. while (wl != EMPTYLIST) {
  635. weakcons = WEAK_CONS( wl );
  636. pp = T_U( PAIR_CAR( weakcons ) );
  637. if (TSCPTAG( PAIR_CAR( weakcons ) ) & 1 &&
  638. pp >= (SCP)sc_firstheapp && pp < (SCP)sc_lastheapp) {
  639. WEAK_CAR( wl ) = PAIR_CAR( weakcons );
  640. PAIR_CAR( weakcons ) = FALSEVALUE;
  641. }
  642. else {
  643. WEAK_CAR( wl ) = FALSEVALUE;
  644. }
  645. wl = WEAK_LINK( wl );
  646. }
  647. }
  648. /* Rebuild the weak cons list. */
  649. static rebuild_weakconsl()
  650. {
  651. TSCP wl, oldcons, newcons, oldcar, newcar, weak;
  652. wl = weakconsl;
  653. weakconsl = EMPTYLIST;
  654. while (wl != EMPTYLIST) {
  655. newcons = resolveptr( (oldcons = WEAK_CONS( wl )) );
  656. newcar = resolveptr( (oldcar = WEAK_CAR( wl )) );
  657. if (oldcons == newcons &&
  658. sc_pagegeneration[ ADDRESS_PAGE( oldcons ) ] ==
  659. sc_current_generation) {
  660. /* Cons cell was not retained so drop from list */
  661. wl = resolveptr( WEAK_LINK( wl ) );
  662. }
  663. else {
  664. if (oldcar != FALSEVALUE &&
  665. (oldcar != newcar ||
  666. sc_pagegeneration[ ADDRESS_PAGE( oldcar ) ] !=
  667. sc_current_generation)) {
  668. /* Object is still in use so restore it's car ptr */
  669. PAIR_CAR( newcons ) = oldcar;
  670. }
  671. weak = MAKE_WEAK;
  672. WEAK_LINK( weak ) = weakconsl;
  673. weakconsl = weak;
  674. WEAK_CONS( weak ) = oldcons;
  675. wl = resolveptr( WEAK_LINK( wl ) );
  676. }
  677. }
  678. }
  679. /* Once all objects are moved, objects needing special action on deletion are
  680. discovered by examining SC_WHENFREED. All objects that have not been moved
  681. are placed on SC_FREED, and those that have been moved are retained on
  682. SC_WHENFREED.
  683. */
  684. static check_unreferenced()
  685. {
  686. TSCP objects, object_procedure, object;
  687. objects = resolveptr( sc_whenfreed );
  688. sc_whenfreed = EMPTYLIST;
  689. while (objects != EMPTYLIST) {
  690. object_procedure = resolveptr( PAIR_CAR( objects ) );
  691. object = PAIR_CAR( object_procedure );
  692. if (object == resolveptr( object ) &&
  693. sc_pagegeneration[ ADDRESS_PAGE( object ) ] ==
  694. sc_current_generation) {
  695. /* Object was not forwarded, so it needs to be cleaned up. */
  696. sc_freed = sc_cons( object_procedure, sc_freed );
  697. }
  698. else {
  699. /* Object was forwarded, so leave it on sc_whenfreed. */
  700. sc_whenfreed = sc_cons( object_procedure, sc_whenfreed );
  701. }
  702. objects = resolveptr( PAIR_CDR( objects ) );
  703. }
  704. }
  705. /* The moves are coordinated by the following function which moves objects on
  706. newly allocated pages until there is nothing left to move.
  707. */
  708. static move_the_heap()
  709. {
  710. int progress, count, weaktodo, unreferenced, page;
  711. SCP myconsp, myextobjp, newp;
  712. myconsp = NULL;
  713. myextobjp = NULL;
  714. weaktodo = 1;
  715. unreferenced = 1;
  716. progress = 1;
  717. while (progress--) {
  718. /* Move all the currently allocated, but unmoved pairs. */
  719. if (myconsp == NULL) {
  720. DELETE_PAGE( cons_pages, page );
  721. if (page) {
  722. sc_pagelink[ page ] = sc_newlist;
  723. sc_newlist = page;
  724. }
  725. myconsp = (SCP)PAGE_ADDRESS( page );
  726. }
  727. if (myconsp != NULL &&
  728. (myconsp != sc_consp || sc_conscnt == 0)) {
  729. count = (PAGEBYTES-ADDRESS_OFFSET( myconsp ))/CONSBYTES;
  730. progress = 1;
  731. while (count-- && (myconsp != sc_consp || sc_conscnt == 0)) {
  732. moving_object = myconsp;
  733. move_ptr( myconsp->pair.car );
  734. move_ptr( myconsp->pair.cdr );
  735. myconsp = (SCP)(((char*)myconsp)+CONSBYTES);
  736. }
  737. if (count == -1) myconsp = NULL;
  738. }
  739. /* Move all currently allocated, but unmoved extended items */
  740. if (myextobjp == NULL) {
  741. DELETE_PAGE( extended_pages, page );
  742. if (page) {
  743. sc_pagelink[ page ] = sc_newlist;
  744. sc_newlist = page;
  745. }
  746. myextobjp = (SCP)PAGE_ADDRESS( page );
  747. }
  748. if (myextobjp != NULL) {
  749. newp = move_object( myextobjp );
  750. if (newp != myextobjp) progress = 1;
  751. myextobjp = newp;
  752. }
  753. /* Find weak references needing cleanup */
  754. if (progress == 0 && weaktodo) {
  755. weaktodo = 0;
  756. rebuild_weakconsl();
  757. progress = 1;
  758. }
  759. /* Find unreferenced objects needing cleanup */
  760. if (progress == 0 && unreferenced) {
  761. unreferenced = 0;
  762. check_unreferenced();
  763. progress = 1;
  764. }
  765. }
  766. if (pointer_errors) abort();
  767. }
  768. /* Objects in the current generation that have references in previous
  769. generations are moved in the following routine.
  770. */
  771. static move_the_generations()
  772. {
  773. int page = sc_genlist, count;
  774. SCP myconsp;
  775. /* Correct the newly allocated pages */
  776. while (page != -1) {
  777. switch (sc_pagetype[ page ]) {
  778. case PAIRTAG:
  779. myconsp = (SCP)PAGE_ADDRESS( page );
  780. count = PAGEBYTES/CONSBYTES;
  781. while (count--) {
  782. move_ptr( myconsp->pair.car );
  783. move_ptr( myconsp->pair.cdr );
  784. myconsp = (SCP)(((char*)myconsp)+CONSBYTES);
  785. }
  786. break;
  787. case EXTENDEDTAG:
  788. move_object( (SCP)PAGE_ADDRESS( page ) );
  789. break;
  790. }
  791. page = sc_pagelink[ page ];
  792. }
  793. }
  794. /* Once all objects are moved, pointers can be corrected to either point to the
  795. new object (when it can be copied), or point to the old object (when the
  796. page is locked). This is done by the following function which takes a
  797. tagged pointer as its argument and returns the new value of the pointer.
  798. */
  799. static TSCP correct( tobj )
  800. TSCP tobj;
  801. {
  802. SCP obj;
  803. if (((int)tobj) & 1) {
  804. obj = T_U( tobj );
  805. if ( (obj->forward.tag != FORWARDTAG) ||
  806. sc_pagelock[ ADDRESS_PAGE( obj ) ] ) return tobj;
  807. return( obj->forward.forward );
  808. }
  809. return( tobj );
  810. }
  811. /* The pointers within extended objects are corrected by the following
  812. function. It is called with a pointer to an object. All objects which
  813. follow it on that page will be corrected.
  814. */
  815. static correct_object( pp )
  816. SCP pp;
  817. {
  818. int page, size, cnt;
  819. PATSCP obj;
  820. page = ADDRESS_PAGE( pp );
  821. while (ADDRESS_PAGE( pp ) == page &&
  822. pp->unsi.gned != ENDOFPAGE &&
  823. (pp != sc_extobjp || sc_extobjwords == 0)) {
  824. switch ( pp->extendedobj.tag ) {
  825. case SYMBOLTAG:
  826. pp->symbol.name = correct( pp->symbol.name );
  827. *pp->symbol.ptrtovalue = correct( *pp->symbol.ptrtovalue );
  828. pp->symbol.propertylist = correct( pp->symbol.propertylist );
  829. size = SYMBOLSIZE;
  830. break;
  831. case STRINGTAG:
  832. size = STRINGSIZE( pp->string.length );
  833. break;
  834. case VECTORTAG:
  835. cnt = pp->vector.length;
  836. obj = &pp->vector.element0;
  837. while (cnt--) {
  838. *obj = correct( *obj );
  839. obj++;
  840. }
  841. size = VECTORSIZE( pp->vector.length );
  842. break;
  843. case PROCEDURETAG:
  844. pp->procedure.closure = correct( pp->procedure.closure );
  845. size = PROCEDURESIZE;
  846. break;
  847. case CLOSURETAG:
  848. pp->closure.closure = correct( pp->closure.closure );
  849. cnt = pp->closure.length;
  850. obj = &pp->closure.var0;
  851. while (cnt--) {
  852. *obj = correct( *obj );
  853. obj++;
  854. }
  855. size = CLOSURESIZE( pp->closure.length );
  856. break;
  857. case CONTINUATIONTAG:
  858. pp->continuation.continuation =
  859. correct( pp->continuation.continuation );
  860. size = CONTINUATIONSIZE( pp->continuation.length );
  861. break;
  862. case FLOAT32TAG:
  863. size = FLOAT32SIZE;
  864. break;
  865. case FLOAT64TAG:
  866. size = FLOAT64SIZE;
  867. break;
  868. case WORDALIGNTAG:
  869. size = WORDALIGNSIZE;
  870. break;
  871. default:
  872. fprintf( stderr,
  873. "***** COLLECT Unknown extended object: %x %x\n",
  874. pp, pp->extendedobj.tag );
  875. abort();
  876. }
  877. pp = (SCP)( ((int*)pp)+size );
  878. }
  879. }
  880. /* Pointer correction to lists of pages is done by the following procedure.
  881. The list is terminated by a -1, and the sc_pagelink field for each page
  882. is set to linkvalue.
  883. */
  884. static correct_pointers( page, linkvalue )
  885. int page, linkvalue;
  886. {
  887. int count, i;
  888. PATSCP ptr;
  889. /* Correct the newly allocated pages */
  890. while (page != -1) {
  891. switch (sc_pagetype[ page ]) {
  892. case PAIRTAG:
  893. ptr = (PATSCP)PAGE_ADDRESS( page );
  894. count = PAGEBYTES/(CONSBYTES/2);
  895. while (count--) {
  896. if ((*((int*)ptr) & 1) &&
  897. (T_U(*ptr)->forward.tag == FORWARDTAG) &&
  898. (sc_pagelock[ ADDRESS_PAGE( *ptr ) ] == 0))
  899. *ptr = T_U(*ptr)->forward.forward;
  900. ptr++;
  901. }
  902. i = page;
  903. page = sc_pagelink[ page ];
  904. sc_pagelink[ i ] = linkvalue;
  905. break;
  906. case EXTENDEDTAG:
  907. correct_object( (SCP)PAGE_ADDRESS( page ) );
  908. i = page;
  909. page = sc_pagelink[ page ];
  910. do sc_pagelink[ i++ ] = linkvalue;
  911. while (i <= sc_lastheappage &&
  912. sc_pagetype[ i ] == BIGEXTENDEDTAG);
  913. break;
  914. }
  915. }
  916. }
  917. /* After pointers have been corrected, the items on locked pages need to have
  918. their correct version (found in the new copy) copied to the old page. In
  919. addition, objects which were not forwarded must be changed so that their
  920. pointers will no longer be followed. This is done by setting the CAR and
  921. CDR of the pair to 0, and turning extended objects into strings. Pages
  922. that are locked are added to sc_genlist so that will be checked on the
  923. next collection.
  924. */
  925. static copyback_locked_pages( locklist )
  926. int locklist;
  927. {
  928. int page, count, vpage;
  929. SCP obj, fobj, sobj;
  930. while (locklist) {
  931. page = locklist;
  932. obj = (SCP)PAGE_ADDRESS( page );
  933. sc_pagelock[ page ] = 0;
  934. sc_pagegeneration[ page ] = sc_next_generation;
  935. locklist = sc_pagelink[ locklist ];
  936. sc_pagelink[ page ] = sc_genlist;
  937. sc_genlist = page;
  938. if (sc_pagetype[ page ] == PAIRTAG) {
  939. /* Move back only the forwarded CONS cells */
  940. count = PAGEBYTES/CONSBYTES;
  941. while (count--) {
  942. if (obj->forward.tag == FORWARDTAG) {
  943. fobj = T_U( obj->forward.forward );
  944. obj->pair.car = fobj->pair.car;
  945. obj->pair.cdr = fobj->pair.cdr;
  946. }
  947. else {
  948. obj->pair.car = 0;
  949. obj->pair.cdr = 0;
  950. }
  951. obj = (SCP)((char*)(obj)+CONSBYTES);
  952. }
  953. }
  954. else if (sc_pagetype[ page ] == EXTENDEDTAG) {
  955. /* Move extra pages into the next generation */
  956. if (obj->wordalign.tag == WORDALIGNTAG) {
  957. obj = (SCP)( ((int*)obj)+WORDALIGNSIZE );
  958. }
  959. count = extendedsize( obj );
  960. vpage = page;
  961. while (count > PAGEWORDS) {
  962. sc_pagegeneration[ ++vpage ] = sc_next_generation;
  963. sc_pagelink[ vpage ] = OKTOSET;
  964. count = count-PAGEWORDS;
  965. }
  966. /* Move back the forwarded extended items */
  967. while (ADDRESS_PAGE( obj ) == page &&
  968. (obj != sc_extobjp || sc_extobjwords == 0) &&
  969. obj->unsi.gned != ENDOFPAGE) {
  970. if (obj->forward.tag == FORWARDTAG) {
  971. sobj = obj;
  972. fobj = T_U( obj->forward.forward );
  973. count = obj->forward.length;
  974. while (count--) {
  975. *((int*)obj) = *((int*)fobj);
  976. obj = (SCP)(((int*)obj)+1);
  977. fobj = (SCP)(((int*)fobj)+1);
  978. }
  979. if (sobj->symbol.tag == SYMBOLTAG) {
  980. vpage = ADDRESS_PAGE( sobj->symbol.ptrtovalue );
  981. if (vpage >= sc_firstheappage &&
  982. vpage <= sc_lastheappage)
  983. sobj->symbol.ptrtovalue = &sobj->symbol.value;
  984. }
  985. }
  986. else if (obj->wordalign.tag == WORDALIGNTAG) {
  987. obj = (SCP)( ((int*)obj)+WORDALIGNSIZE );
  988. }
  989. else {
  990. count = extendedsize( obj );
  991. obj->string.length = ((count-2)*4)+3;
  992. obj->string.tag = STRINGTAG;
  993. obj = (SCP)( ((int*)obj)+count );
  994. }
  995. }
  996. }
  997. }
  998. }
  999. /* This function is called to check the obarray to make sure that it is
  1000. intact.
  1001. */
  1002. static int check_obarray()
  1003. {
  1004. int i, len, page;
  1005. PATSCP ep;
  1006. TSCP lp, symbol, value;
  1007. SCP obarray;
  1008. obarray = T_U( sc_obarray );
  1009. if (TSCPTAG( sc_obarray ) != EXTENDEDTAG ||
  1010. obarray->vector.tag != VECTORTAG) {
  1011. fprintf( stderr, "***** COLLECT OBARRAY is not a vector %x\n",
  1012. sc_obarray );
  1013. abort();
  1014. }
  1015. len = obarray->vector.length;
  1016. if (len != 1023) {
  1017. fprintf( stderr, "***** COLLECT OBARRAY length is wrong %x\n",
  1018. sc_obarray );
  1019. abort();
  1020. }
  1021. ep = &obarray->vector.element0;
  1022. for (i = 0; i < len; i++) {
  1023. lp = *ep++;
  1024. while (lp != EMPTYLIST) {
  1025. if (TSCPTAG( lp ) != PAIRTAG) {
  1026. fprintf( stderr,
  1027. "***** COLLECT OBARRAY element is not a list %x\n",
  1028. lp );
  1029. abort();
  1030. }
  1031. symbol = T_U( lp )->pair.car;
  1032. if (T_U( symbol )->symbol.tag != SYMBOLTAG) {
  1033. fprintf( stderr,
  1034. "***** COLLECT OBARRAY entry is not a symbol %x\n",
  1035. symbol );
  1036. abort();
  1037. }
  1038. page = ADDRESS_PAGE( symbol );
  1039. if (sc_pagegeneration[ page ] & 1 &&
  1040. sc_pagegeneration[ page ] != sc_current_generation) {
  1041. fprintf( stderr,
  1042. "***** COLLECT OBARRAY symbol generation error %x\n",
  1043. symbol );
  1044. abort();
  1045. }
  1046. value = *T_U( symbol )->symbol.ptrtovalue;
  1047. page = ADDRESS_PAGE( value );
  1048. if (TSCPTAG( value ) & 1 &&
  1049. S2CPAGE( page ) &&
  1050. sc_pagegeneration[ page ] & 1 &&
  1051. sc_pagegeneration[ page ] != sc_current_generation) {
  1052. fprintf( stderr,
  1053. "***** COLLECT OBARRAY value generation error %x\n",
  1054. symbol );
  1055. abort();
  1056. }
  1057. if (TSCPTAG( value ) & 1 &&
  1058. (~sc_pagegeneration[ ADDRESS_PAGE( symbol ) ]) & 1 &&
  1059. sc_pagegeneration[ page ] == sc_current_generation &&
  1060. sc_pagelink[ ADDRESS_PAGE( symbol ) ] == 0 &&
  1061. ADDRESS_PAGE( symbol ) ==
  1062. ADDRESS_PAGE( T_U( symbol )->symbol.ptrtovalue )) {
  1063. fprintf( stderr,
  1064. "***** COLLECT OBARRAY missed a top-level set! %x\n",
  1065. symbol );
  1066. abort();
  1067. }
  1068. if (sc_pagetype[ ADDRESS_PAGE( symbol ) ] != EXTENDEDTAG) {
  1069. fprintf( stderr,
  1070. "***** COLLECT OBARRAY symbol page type error %x\n",
  1071. symbol );
  1072. abort();
  1073. }
  1074. lp = T_U( lp )->pair.cdr;
  1075. }
  1076. }
  1077. }
  1078. /* The following procedure verifies that a pointer is correct. */
  1079. static check_ptr( tpp )
  1080. TSCP tpp;
  1081. {
  1082. int page;
  1083. page = ADDRESS_PAGE( tpp );
  1084. if (((int) tpp) & 1) {
  1085. if (S2CPAGE( page )) {
  1086. if ((sc_pagegeneration[ page ] != sc_current_generation &&
  1087. sc_pagegeneration[ page ] & 1) ||
  1088. sc_pagetype[ page ] != TSCPTAG( tpp )) {
  1089. pointererror( "%x fails check_ptr\n", T_U( tpp ) );
  1090. }
  1091. }
  1092. else if (TSCPTAG( tpp ) == PAIRTAG) {
  1093. pointererror( "%x fails check_ptr\n", T_U( tpp ) );
  1094. }
  1095. }
  1096. }
  1097. /* A page of objects is checked by the following procedure. */
  1098. static SCP check_object( pp )
  1099. SCP pp;
  1100. {
  1101. int page, size, cnt, vpage;
  1102. PATSCP obj;
  1103. page = ADDRESS_PAGE( pp );
  1104. while (ADDRESS_PAGE( pp ) == page &&
  1105. (pp != sc_extobjp || sc_extobjwords == 0) &&
  1106. pp->unsi.gned != ENDOFPAGE) {
  1107. moving_object = pp;
  1108. switch ( pp->extendedobj.tag ) {
  1109. case SYMBOLTAG:
  1110. check_ptr( pp->symbol.name );
  1111. vpage = ADDRESS_PAGE( pp->symbol.ptrtovalue );
  1112. check_ptr( *pp->symbol.ptrtovalue );
  1113. check_ptr( pp->symbol.propertylist );
  1114. size = SYMBOLSIZE;
  1115. break;
  1116. case STRINGTAG:
  1117. size = STRINGSIZE( pp->string.length );
  1118. break;
  1119. case VECTORTAG:
  1120. cnt = pp->vector.length;
  1121. obj = &pp->vector.element0;
  1122. while (cnt--) check_ptr( *obj++ );
  1123. size = VECTORSIZE( pp->vector.length );
  1124. break;
  1125. case PROCEDURETAG:
  1126. check_ptr( pp->procedure.closure );
  1127. size = PROCEDURESIZE;
  1128. break;
  1129. case CLOSURETAG:
  1130. check_ptr( pp->closure.closure );
  1131. cnt = pp->closure.length;
  1132. obj = &pp->closure.var0;
  1133. while (cnt--) check_ptr( *obj++ );
  1134. size = CLOSURESIZE( pp->closure.length );
  1135. break;
  1136. case CONTINUATIONTAG:
  1137. check_ptr( pp->continuation.continuation );
  1138. size = CONTINUATIONSIZE( pp->continuation.length );
  1139. break;
  1140. case FLOAT32TAG:
  1141. size = FLOAT32SIZE;
  1142. break;
  1143. case FLOAT64TAG:
  1144. size = FLOAT64SIZE;
  1145. break;
  1146. case WORDALIGNTAG:
  1147. size = WORDALIGNSIZE;
  1148. break;
  1149. default:
  1150. pointererror( "%x is not a valid extended object tag\n",
  1151. pp->extendedobj.tag );
  1152. }
  1153. pp = (SCP)( ((int*)pp)+size );
  1154. }
  1155. if (ADDRESS_PAGE( pp ) == page && pp == sc_extobjp &&
  1156. sc_extobjwords != 0)
  1157. return( pp );
  1158. return( NULL );
  1159. }
  1160. /* A page of pairs is checkled by the following procedure. */
  1161. static void check_pairs( pp )
  1162. SCP pp;
  1163. {
  1164. int count;
  1165. PATSCP ptr;
  1166. ptr = (PATSCP)pp;
  1167. count = (PAGEBYTES/CONSBYTES)*2;
  1168. while (count-- &&
  1169. (ptr != (PATSCP)sc_consp || sc_conscnt == 0)) {
  1170. moving_object = (SCP)(((unsigned)ptr) & 0xfffffff8);
  1171. check_ptr( *ptr );
  1172. ptr++;
  1173. }
  1174. }
  1175. /* The following function can be called to check that all objects in the
  1176. heap are valid.
  1177. */
  1178. static void check_heap( )
  1179. {
  1180. int i;
  1181. /* Verify that all pages containing pairs are in good shape */
  1182. for (i = sc_firstheappage; i <= sc_lastheappage; i++) {
  1183. if ((sc_pagegeneration[ i ] == sc_current_generation ||
  1184. ~sc_pagegeneration[ i ] & 1) &&
  1185. sc_pagegeneration[ i ] != 0) {
  1186. if (sc_pagetype[ i ] == PAIRTAG) {
  1187. check_pairs( (SCP)PAGE_ADDRESS( i ) );
  1188. }
  1189. if (sc_pagetype[ i ] == EXTENDEDTAG) {
  1190. check_object( (SCP)PAGE_ADDRESS( i ) );
  1191. }
  1192. }
  1193. }
  1194. if (pointer_errors) abort();
  1195. }
  1196. /* Check the weakconsl for proper format. */
  1197. static void check_weakconsl()
  1198. {
  1199. TSCP wl = weakconsl;
  1200. while (wl != EMPTYLIST) {
  1201. check_ptr( wl );
  1202. check_ptr( WEAK_LINK( wl ) );
  1203. check_ptr( WEAK_CONS( wl ) );
  1204. check_ptr( WEAK_CAR( wl ) );
  1205. wl = WEAK_LINK( wl );
  1206. }
  1207. if (pointer_errors) abort();
  1208. }
  1209. /* Garbage collection is invoked to attempt to recover free storage when a
  1210. request for storage cannot be met. It will recover using a generational
  1211. version of the "mostly copying" method. See the .h file or the research
  1212. reports for more details.
  1213. */
  1214. TSCP sc_collect_v;
  1215. TSCP sc_collect()
  1216. {
  1217. int i, wasallocated;
  1218. TSCP constl, fl;
  1219. if (sc_collecting) {
  1220. fprintf( stderr, "***** COLLECT Out of space during collection\n" );
  1221. abort();
  1222. }
  1223. sc_gcinprogress( 1 );
  1224. sc_initiallink = ~OKTOSET;
  1225. wasallocated = sc_allocatedheappages;
  1226. if (sc_gcinfo == 2) {
  1227. /* Perform additional consistency checks */
  1228. check_heap();
  1229. check_obarray();
  1230. check_weakconsl();
  1231. }
  1232. if (sc_gcinfo) {
  1233. fprintf( stderr,
  1234. "\n***** COLLECT %d%% allocated (%d%% waste, %d MB) -> \n",
  1235. (wasallocated*100)/sc_heappages,
  1236. (sc_extwaste*100)/(sc_heappages*PAGEWORDS),
  1237. (sc_heappages*PAGEBYTES+ONEMB/2)/ONEMB );
  1238. }
  1239. getrusage( 0, &startru );
  1240. /* Zero the current cons block, end the current extended block,
  1241. initialize sc_locklist, advance the generation.
  1242. */
  1243. sc_conscnt = sc_conscnt+sc_conscnt;
  1244. while (sc_conscnt-- > 0) {
  1245. *((int*)sc_consp) = 0;
  1246. sc_consp = (SCP)(((int*)sc_consp)+1);
  1247. }
  1248. sc_conscnt = 0;
  1249. if (sc_extobjwords) {
  1250. sc_extobjp->unsi.gned = ENDOFPAGE;
  1251. sc_extobjwords = 0;
  1252. }
  1253. sc_extwaste = 0;
  1254. sc_allocatedheappages = 0;
  1255. sc_newlist = -1;
  1256. sc_locklist = 0;
  1257. sc_lockcnt = 0;
  1258. sc_next_generation = INC_GENERATION( sc_current_generation );
  1259. /* Hide the car's of pairs on the weakconsl. */
  1260. save_weakconsl();
  1261. /* Move the globals, display, and constants */
  1262. for ( i = 0; i < sc_globals->count; i++ ) {
  1263. move_ptr( *(sc_globals->ptrs[ i ]) );
  1264. }
  1265. for ( i = 0; i < sc_maxdisplay; i++ ) move_ptr( sc_display[ i ] );
  1266. for ( i = 0; i < sc_constants->count; i++ ) {
  1267. move_ptr( *(sc_constants->ptrs[ i ]) );
  1268. }
  1269. /* Look into the stack and the registers and treat anything that
  1270. might be a pointer as a root and move it.
  1271. */
  1272. trace_stack_and_registers();
  1273. /* Lock down user program's frozen objects. */
  1274. fl = sc__2afrozen_2dobjects_2a_v;
  1275. while (TSCPTAG( fl ) == PAIRTAG) {
  1276. move_continuation_ptr( T_U( PAIR_CAR( fl ) ) );
  1277. fl = PAIR_CDR( fl );
  1278. }
  1279. /* Move new objects referenced in previous generations */
  1280. move_the_generations();
  1281. /* Continue moving the current generation until it terminates
  1282. and then handle weak pointers and unreferenced.
  1283. */
  1284. move_the_heap();
  1285. sc_allocatedheappages = sc_allocatedheappages+sc_lockcnt;
  1286. /* Fully allocate partial pages */
  1287. sc_conscnt = sc_conscnt+sc_conscnt;
  1288. while (sc_conscnt-- > 0) {
  1289. *((int*)sc_consp) = 0;
  1290. sc_consp = (SCP)(((int*)sc_consp)+1);
  1291. }
  1292. sc_conscnt = 0;
  1293. if (sc_extobjwords) {
  1294. sc_extobjp->unsi.gned = ENDOFPAGE;
  1295. sc_extobjwords = 0;
  1296. }
  1297. /* Correct pointers in the copied heap */
  1298. correct_pointers( sc_newlist, sc_initiallink );
  1299. /* Correct pointers in previous generations */
  1300. correct_pointers( sc_genlist, 0 );
  1301. /* Correct pointers in globals, display, and constants */
  1302. for ( i = 0; i < sc_globals->count; i++ )
  1303. *(sc_globals->ptrs[ i ]) = correct( *(sc_globals->ptrs[ i ]) );
  1304. for ( i = 0; i < sc_maxdisplay; i++ )
  1305. sc_display[ i ] = correct( sc_display[ i ] );
  1306. for ( i = 0; i < sc_constants->count; i++ )
  1307. *(sc_constants->ptrs[ i ]) = correct( *(sc_constants->ptrs[ i ]) );
  1308. /* Copy back the locked objects and add locked pages to sc_genlist */
  1309. sc_genlist = -1;
  1310. copyback_locked_pages( sc_locklist );
  1311. /* Step to the next odd generation */
  1312. sc_next_generation = sc_current_generation =
  1313. INC_GENERATION( sc_next_generation );
  1314. sc_generationpages = sc_generationpages+sc_allocatedheappages;
  1315. sc_allocatedheappages = sc_generationpages;
  1316. /* Finish up */
  1317. getrusage( 0, &stopru );
  1318. updategcru();
  1319. if (sc_gcinfo) {
  1320. fprintf( stderr,
  1321. " %d%% locked %d%% retained %d user ms",
  1322. (sc_lockcnt*100)/sc_heappages,
  1323. (sc_generationpages*100)/sc_heappages,
  1324. stopru.ru_utime.tv_sec*1000+stopru.ru_utime.tv_usec/1000 );
  1325. fprintf( stderr,
  1326. " %d system ms %d page faults\n",
  1327. stopru.ru_stime.tv_sec*1000+stopru.ru_stime.tv_usec/1000,
  1328. stopru.ru_majflt );
  1329. }
  1330. if (sc_gcinfo == 2) {
  1331. /* Perform additional consistency checks */
  1332. check_heap();
  1333. check_obarray();
  1334. check_weakconsl();
  1335. }
  1336. /* Compact the whole heap if > sc_limit % of pages allocated */
  1337. sc_initiallink = OKTOSET;
  1338. sc_gcinprogress( 0 );
  1339. if ((sc_allocatedheappages*100)/sc_heappages > sc_limit) {
  1340. sc_collect_2dall();
  1341. if (sc_allocatedheappages > (sc_limit*sc_heappages*8)/1000) {
  1342. MUTEXON;
  1343. sc_expandheap();
  1344. MUTEXOFF;
  1345. }
  1346. }
  1347. if (sc_after_2dcollect_v != FALSEVALUE)
  1348. sc_apply_2dtwo( sc_after_2dcollect_v,
  1349. sc_cons( C_FIXED( sc_heappages*PAGEBYTES ),
  1350. sc_cons( C_FIXED( sc_allocatedheappages*PAGEBYTES ),
  1351. sc_cons( C_FIXED( sc_limit ),
  1352. EMPTYLIST ) ) ) );
  1353. return( TRUEVALUE );
  1354. }
  1355. /* A complete garbage collection can be forced by calling the following
  1356. procedure.
  1357. */
  1358. TSCP sc_collect_2dall_v;
  1359. TSCP sc_collect_2dall()
  1360. {
  1361. int i,
  1362. save_sc_limit = sc_limit;
  1363. MUTEXON;
  1364. sc_limit = 100;
  1365. if (sc_generationpages != sc_allocatedheappages) sc_collect();
  1366. sc_limit = save_sc_limit;
  1367. MUTEXOFF;
  1368. MUTEXON;
  1369. sc_next_generation =
  1370. INC_GENERATION( INC_GENERATION( sc_next_generation ) );
  1371. sc_current_generation = sc_next_generation;
  1372. for (i = sc_firstheappage; i <= sc_lastheappage; i++) {
  1373. if (sc_pagegeneration[ i ] != 0 && ~sc_pagegeneration[ i ] & 1)
  1374. sc_pagegeneration[ i ] = sc_current_generation;
  1375. }
  1376. sc_generationpages = 0;
  1377. sc_genlist = -1;
  1378. sc_limit = 100;
  1379. sc_collect();
  1380. sc_limit = save_sc_limit;
  1381. MUTEXOFF;
  1382. return( TRUEVALUE );
  1383. }
  1384. /* Pages in the heap are allocated by the following function. It is called
  1385. with a page count and sets the appropriate allocation pointers as
  1386. required. The sc_pagegeneration, sc_pagelink, sc_pagetype fields are
  1387. set for each page here. The garbage collector is invoked as needed.
  1388. */
  1389. static int allocatepage_failed = 0; /* Set following collection, cleared on
  1390. successful allocation */
  1391. static allocatepage( count, tag )
  1392. int count, tag;
  1393. {
  1394. int start, page, freecnt, generation;
  1395. if ((count+sc_allocatedheappages) > sc_heappages/2) {
  1396. failed:
  1397. if ((allocatepage_failed || sc_collecting) &&
  1398. sc_expandheap() == 0) {
  1399. fprintf( stderr,
  1400. "***** ALLOCATEPAGE cannot allocate %d bytes",
  1401. count*PAGEBYTES );
  1402. fprintf( stderr, " with %d %% of heap allocated\n",
  1403. (sc_allocatedheappages*100)/sc_heappages );
  1404. exit( 1 );
  1405. }
  1406. if (sc_collecting == 0) sc_collect();
  1407. allocatepage_failed = 1;
  1408. return;
  1409. }
  1410. start = sc_freepage;
  1411. freecnt = 0;
  1412. do {
  1413. generation = sc_pagegeneration[ sc_freepage ];
  1414. if (generation & 1 && generation != sc_current_generation) {
  1415. if (freecnt == 0) page = sc_freepage;
  1416. freecnt++;
  1417. }
  1418. else
  1419. freecnt = 0;
  1420. if (sc_freepage == sc_lastheappage) {
  1421. if (freecnt != count) freecnt = 0;
  1422. sc_freepage = sc_firstheappage;
  1423. }
  1424. else sc_freepage++;
  1425. if (sc_freepage == start) goto failed;
  1426. } while (count != freecnt);
  1427. allocatepage_failed = 0;
  1428. sc_allocatedheappages = sc_allocatedheappages+count;
  1429. sc_pagegeneration[ page ] = sc_next_generation;
  1430. sc_pagetype[ page ] = tag;
  1431. sc_pagelink[ page ] = sc_initiallink;
  1432. if (tag == PAIRTAG) {
  1433. sc_conscnt = PAGEBYTES/CONSBYTES;
  1434. sc_consp = (SCP)PAGE_ADDRESS( page );
  1435. if (sc_collecting) QUEUE_PAGE( cons_pages, page );
  1436. }
  1437. else {
  1438. sc_extobjp = (SCP)PAGE_ADDRESS( page );
  1439. sc_extobjwords = count*PAGEWORDS;
  1440. if (sc_collecting) QUEUE_PAGE( extended_pages, page );
  1441. while (--count) {
  1442. sc_pagegeneration[ ++page ] = sc_next_generation;
  1443. sc_pagetype[ page ] = BIGEXTENDEDTAG;
  1444. sc_pagelink[ page ] = sc_initiallink;
  1445. }
  1446. }
  1447. }
  1448. /* When a pointer to a new object may be stored in a old page, the following
  1449. procedure is called to add the old page to the list of changed older pages
  1450. and then do the assignment. N.B. set-top-level-value! may set global
  1451. values outside the heap.
  1452. */
  1453. TSCP sc_setgeneration( a, b )
  1454. TSCP* a;
  1455. TSCP b;
  1456. {
  1457. int oldpage = ADDRESS_PAGE( a );
  1458. MUTEXON;
  1459. if (S2CPAGE( oldpage ) && sc_pagelink[ oldpage ] == 0) {
  1460. if (sc_pagetype[ oldpage ] == PAIRTAG) {
  1461. if (sc_pagegeneration[ oldpage ] == sc_current_generation) {
  1462. sc_pagelink[ oldpage ] = OKTOSET;
  1463. }
  1464. else {
  1465. sc_pagelink[ oldpage ] = sc_genlist;
  1466. sc_genlist = oldpage;
  1467. }
  1468. }
  1469. else {
  1470. while (sc_pagetype[ oldpage ] == BIGEXTENDEDTAG) oldpage--;
  1471. if (sc_pagegeneration[ oldpage ] == sc_current_generation) {
  1472. sc_pagelink[ oldpage ] = OKTOSET;
  1473. }
  1474. else {
  1475. sc_pagelink[ oldpage ] = sc_genlist;
  1476. sc_genlist = oldpage;
  1477. }
  1478. while (++oldpage < sc_lastheappage &&
  1479. sc_pagetype[ oldpage ] == BIGEXTENDEDTAG) {
  1480. sc_pagelink[ oldpage ] = OKTOSET;
  1481. }
  1482. }
  1483. }
  1484. *a = b;
  1485. MUTEXOFF;
  1486. return( b );
  1487. }
  1488. /* Heap based storage is allocated by the following function. It is called
  1489. with a word count and a value to put in the first word. It will return
  1490. an UNTAGGED pointer to the storage. Note that the minimum permissible
  1491. allocation size is two words.
  1492. N.B. IT IS THE CALLER'S RESPONSIBILITY TO ASSURE THAT SIGNALS DO NOT
  1493. CAUSE PROBLEMS DURING ALLOCATION.
  1494. */
  1495. SCP sc_allocateheap( wordsize, tag, rest )
  1496. int wordsize, tag, rest;
  1497. {
  1498. SCP alloc;
  1499. int isastring = (t

Large files files are truncated, but you can click here to view the full file