home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume20 / c-gc / part02 < prev    next >
Text File  |  1989-09-17  |  41KB  |  1,343 lines

  1. Subject:  v20i003:  C memory garbage collector, Part02/02
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Hans Boehm <boehm@rice.edu>
  7. Posting-number: Volume 20, Issue 3
  8. Archive-name: c-gc/part02
  9.  
  10. echo 'Start of distribution file ../gc.shar.02:'
  11. echo 'Extracting README...'
  12. sed 's/^X//' > README << '/'
  13. XCopyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  14. XThis material may be freely distributed, provided this notice is retained.
  15. XThis material is provided as is, with no warranty expressed or implied.
  16. XUse at your own risk.
  17. X
  18. X  This collector was developed as a part of research projects supported in
  19. Xpart by the National Science Foundation and the Defense Advance Research
  20. XProjects Agency.  The SPARC specific code was contributed by Mark Weiser
  21. X(weiser.pa@xerox.com).  The Encore Multimax modifications were supplied by
  22. XKevin Kenny (kenny@m.cs.uiuc.edu).  The adaptation to the RT is largely due
  23. Xto Vernon Lee, on machines made available by IBM. (Blame for misinstallation
  24. Xof those modifications goes to the first author, however.) Some of the
  25. Ximprovements incorporated in this version were suggested by David Chase at
  26. XOlivetti Research.
  27. X
  28. X  This is intended to be a general purpose, garbage collecting storage
  29. Xallocator.  The algorithms used are described in:
  30. X
  31. XBoehm, H., and M. Weiser, "Garbage Collection in an Uncooperative Environment",
  32. XSoftware Practice & Experience, September 1988, pp. 807-820.
  33. X
  34. X  Many of the ideas underlying the collector have previously been explored
  35. Xby others.  (We discovered recently that Doug McIlroy wrote a more or less
  36. Xsimilar collector that is part of version 8 UNIX (tm).)  However none of this
  37. Xwork appears to have been widely disseminated.
  38. X
  39. X  The tools for detecting storage leaks described in the above paper
  40. Xare not included here.  There is some hope that they might be released
  41. Xby Xerox in the future.
  42. X
  43. X  Since the collector does not require pointers to be tagged, it does not
  44. Xattempt to insure that all inaccessible storage is reclaimed.  However,
  45. Xin our experience, it is typically more successful at reclaiming unused
  46. Xmemory than most C programs using explicit deallocation.
  47. X
  48. X  In the following, an "object" is defined to be a region of memory allocated
  49. Xby the routines described below.  
  50. X
  51. X  Any objects not intended to be collected must be pointed to either
  52. Xfrom other such accessible objects, or from the registers,
  53. Xstack, data, or statically allocated bss segments.  It is usually assumed
  54. Xthat all such pointers point to the beginning of the object.  (This does
  55. Xnot disallow interior pointers; it simply requires that there must be a
  56. Xpointer to the beginning of every accessible object, in addition to any
  57. Xinterior pointers.  Conditionally compiled code to check for pointers to the
  58. Xinteriors of objects is supplied.  As explained in "runtime.h", this
  59. Xmay create other problems, however.)
  60. X  Note that pointers inside memory allocated by the standard "malloc" are not
  61. Xseen by the garbage collector.  Thus objects pointed to only from such a
  62. Xregion may be prematurely deallocated.  It is thus suggested that the
  63. Xstandard "malloc" be used only for memory regions, such as I/O buffers, that
  64. Xare guaranteed not to contain pointers.  Pointers in C language automatic,
  65. Xstatic, or register variables, are correctly recognized.
  66. X  The collector is designed to minimize stack growth if link fields inside
  67. Xstructures are allocated first.  (Normally only linked lists of lengths
  68. Xexceeding about 100000 will cause this to be noticable.)
  69. X  Signal processing for most signals is deferred during collection. (This
  70. Xis not done on the MIPS machine under System V, where this seem to require
  71. Xmany system calls.  If signal handling is desired, the user will probably
  72. Xfind it necessary to suspend those signals that are actually used.)
  73. X  As distributed, the collector produces garbage collection statistics
  74. Xduring every collection.  Once the collector is known to operate properly,
  75. Xthese can be suppressed by undefining the appropriate macros at the top
  76. Xof "runtime.h".  (The given statistics exhibit a few peculiarities.
  77. XThings don't appear to add up for a variety of reasons, most notably
  78. Xfragmentation losses.  These are probably much more significant for the
  79. Xcontrived program "test.c" than for your application.)
  80. X  The collector currently is designed to run essentially unmodified on
  81. Xthe following machines:
  82. X
  83. X        Sun 3
  84. X        Sun 4  (except under some versions of 3.2)
  85. X        Vax under Berkeley UNIX
  86. X        Sequent Symmetry  (no concurrency)
  87. X        Encore Multimax   (no concurrency)
  88. X        MIPS M/120 (and presumably M/2000) (System V)
  89. X        IBM PC/RT  (Berkeley UNIX)
  90. X
  91. X  For these machines you should check the beginning of runtime.h
  92. Xto verify that the machine type is correctly defined.  On an Encore Multimax,
  93. XMIPS M/120, or a PC/RT, you will also need to make changes to the
  94. XMakefile, as described by comments there.
  95. X  In all cases we assume that pointer alignment is consistent with that
  96. Xenforced by the standard C compilers.  If you use a nonstandard compiler
  97. Xyou may have to adjust the alignment parameters defined in runtime.h.
  98. X  On a MIPS machine or PC/RT, we assume that no calls to sbrk occur during a
  99. Xcollection. (This is necessary due to the way stack expansion works on these
  100. Xmachines.) This may become false if certain kinds of I/O calls are inserted
  101. Xinto the collector.
  102. X
  103. X  For machines not already mentioned, the following are likely to require
  104. Xchange:
  105. X
  106. X1.  The parameters at the top of runtime.h and the definition of
  107. X    TMP_POINTER_MASK further down in the same file.
  108. X2.  mach_dep.c.  This includes routines to mark from registers,
  109. X    and to save registers not normally preserved by the C compiler.
  110. X    (The latter should not be necessary unless assembly language calls
  111. X    to the allocator are used.)  If your machine does not allow in-line
  112. X    assembly code, this may be replaced by a .s file (as we did for the MIPS
  113. X    machine and the PC/RT).
  114. X
  115. X  For a different UN*X version or different machine using the Motorola 68000,
  116. XVax, SPARC, 80386, NS 32000, PC/RT, or MIPS architecture, it should frequently
  117. Xsuffice to change definitions in runtime.h.
  118. X
  119. X  The following routines are intended to be directly called by the user.
  120. XNote that only gc_malloc and gc_init are necessary.  The remaining routines
  121. Xare used solely to enhance performance.  It is suggested that they be used
  122. Xonly after initial debugging.
  123. X
  124. X1)  gc_init()
  125. X    - called once before allocation to initialize the collector.
  126. X
  127. X2)  gc_malloc(nbytes)
  128. X    - allocate an object of size nbytes.  Unlike malloc, the object is
  129. X      cleared before being returned to the user.  (For even better performance,
  130. X      it may help to expand the relevant part of gc_malloc in line.
  131. X      This is done by the Russell compiler, for example.)  Gc_malloc will
  132. X      invoke the garbage collector when it determines this to be appropriate.
  133. X      (A number of previous collector bugs resulted in objects not getting
  134. X      completely cleared.  We claim these are all fixed.  But if you encounter
  135. X      problems, this is a likely source to check for.  The collector tries
  136. X      hard to avoid clearing any words that it doesn't have to.  Thus this
  137. X      is a bit subtle.)
  138. X      
  139. X
  140. X3)  gc_malloc_atomic(nbytes)
  141. X    - allocate an object of size nbytes that is guaranteed not to contain any
  142. X      pointers.  The returned object is not guaranteed to be cleeared.
  143. X      (Can always be replaced by gc_malloc, but results in faster collection
  144. X      times.  The collector will probably run faster if large character
  145. X      arrays, etc. are allocated with gc_malloc_atomic than if they are
  146. X      statically allocated.)
  147. X
  148. X4)  gc_free(object)
  149. X    - explicitly deallocate an object returned by gc_malloc or
  150. X      gc_malloc_atomic.  Not necessary, but can be used to minimize
  151. X      collections if performance is critical.
  152. X
  153. X5)  expand_hp(number_of_4K_blocks)
  154. X    - Explicitly increase the heap size.  (This is normally done automatically
  155. X      if a garbage collection failed to reclaim enough memory.  Explicit
  156. X      calls to expand_hp may prevent unnecessarily frequent collections at
  157. X      program startup.)
  158. X
  159. X  The global variable dont_gc can be set to a non-zero value to inhibit
  160. Xcollections, e.g. during a time-critical section of code.  (This may cause
  161. Xotherwise unnecessary exansion of the process' memory.)
  162. X  The variable non_gc_bytes, which is normally 0, may be changed to reflect
  163. Xthe amount of memory allocated by the above routines that should not be
  164. Xconsidered as a candidate for collection.  Collections are inhibited
  165. Xif this exceeds a given fraction (currently 3/4) of the total heap size.
  166. XThe heap is simply expanded instead.  Careless use may, of course, result
  167. Xin excessive memory consumption.
  168. X  Some additional tuning is possible through the parameters defined
  169. Xnear the top of runtime.h.
  170. X  
  171. X  The two gc_malloc routines may be declared to return a suitable pointer
  172. Xtype.  It is not intended that runtime.h be included by the user program.
  173. XIf only gc_malloc is intended to be used, it might be appropriate to define:
  174. X
  175. X#define malloc(n) gc_malloc(n)
  176. X#define calloc(m,n) gc_malloc((m)*(n))
  177. X
  178. X  No attempt is made to use obscure names for garbage collector routines
  179. Xand data structures.  Name conflicts are possible.  (Running "nm gc.o"
  180. Xshould identify names to be avoided.)
  181. X
  182. X  Please address bug reports to boehm@rice.edu.
  183. /
  184. echo 'Extracting allochblk.c...'
  185. sed 's/^X//' > allochblk.c << '/'
  186. X#define DEBUG
  187. X#undef DEBUG
  188. X#include <stdio.h>
  189. X#include "runtime.h"
  190. X/**/
  191. X/* allocate/free routines for heap blocks
  192. X/* Note that everything called from outside the garbage collector
  193. X/* should be prepared to abort at any point as the result of a signal.
  194. X/**/
  195. X
  196. X/*
  197. X * Free heap blocks are kept on a list sorted by address.
  198. X * The hb_hdr.hbh_sz field of a free heap block contains the length
  199. X * (in bytes) of the entire block.
  200. X * Neighbors are coalesced.
  201. X */
  202. X
  203. Xstruct hblk *savhbp = (struct hblk *)0;  /* heap block preceding next */
  204. X                     /* block to be examined by   */
  205. X                     /* allochblk.                */
  206. X
  207. X/*
  208. X * Return 1 if there is a heap block sufficient for object size sz,
  209. X * 0 otherwise.  Advance savhbp to point to the block prior to the
  210. X * first such block.
  211. X */
  212. Xint sufficient_hb(sz)
  213. Xint sz;
  214. X{
  215. Xregister struct hblk *hbp;
  216. Xstruct hblk *prevhbp;
  217. Xint size_needed, size_avail;
  218. Xint first_time = 1;
  219. X
  220. X    size_needed = WORDS_TO_BYTES(sz>0? sz : -sz);
  221. X    size_needed = (size_needed+sizeof(struct hblkhdr)+HBLKSIZE-1) & ~HBLKMASK;
  222. X#   ifdef DEBUG
  223. X    printf("sufficient_hb: sz = %d, size_needed = 0x%X\n", sz, size_needed);
  224. X#   endif
  225. X    /* search for a big enough block in free list */
  226. X    hbp = savhbp;
  227. X    for(;;) {
  228. X        prevhbp = hbp;
  229. X        hbp = ((prevhbp == (struct hblk *)0)
  230. X            ? hblkfreelist
  231. X            : prevhbp->hb_next);
  232. X
  233. X        if( prevhbp == savhbp && !first_time) {
  234. X        /* no sufficiently big blocks on free list */
  235. X        return(0);
  236. X        }
  237. X        first_time = 0;
  238. X        if( hbp == (struct hblk *)0 ) continue;
  239. X        size_avail = hbp->hb_sz;
  240. X        if( size_avail >= size_needed ) {
  241. X        savhbp = prevhbp;
  242. X        return(1);
  243. X        }
  244. X    }
  245. X}
  246. X
  247. X/*
  248. X * Allocate (and return pointer to) a heap block
  249. X *   for objects of size |sz|.
  250. X *
  251. X * NOTE: Caller is responsible for adding it to global hblklist
  252. X *       and for building an object freelist in it.
  253. X *
  254. X * The new block is guaranteed to be cleared if sz > 0.
  255. X */
  256. Xstruct hblk *
  257. Xallochblk(sz)
  258. Xlong sz;
  259. X{
  260. X    register struct hblk *thishbp;
  261. X    register struct hblk *hbp;
  262. X    struct hblk *prevhbp;
  263. X    long size_needed,            /* number of bytes in requested objects */
  264. X         uninit,                 /* => Found uninitialized block         */
  265. X         size_avail;
  266. X    int first_time = 1;
  267. X
  268. X    char *sbrk();            /* data segment size increasing    */
  269. X    char *brk();            /* functions            */
  270. X
  271. X    size_needed = WORDS_TO_BYTES(sz>0? sz : -sz);
  272. X    size_needed = (size_needed+sizeof(struct hblkhdr)+HBLKSIZE-1) & ~HBLKMASK;
  273. X#   ifdef DEBUG
  274. X    printf("(allochblk) sz = %x, size_needed = 0x%X\n", sz, size_needed);
  275. X#   endif
  276. X
  277. X    /* search for a big enough block in free list */
  278. X    hbp = savhbp;
  279. X    for(;;) {
  280. X
  281. X        prevhbp = hbp;
  282. X        hbp = ((prevhbp == (struct hblk *)0)
  283. X                    ? hblkfreelist
  284. X            : prevhbp->hb_next);
  285. X
  286. X        if( prevhbp == savhbp && !first_time) {
  287. X        /* no sufficiently big blocks on free list, */
  288. X        /* let thishbp --> a newly-allocated block, */
  289. X        /* free it (to merge into existing block    */
  290. X        /* list) and start the search again, this   */
  291. X        /* time with guaranteed success.            */
  292. X                  int size_to_get = size_needed + hincr * HBLKSIZE;
  293. X          extern int holdsigs();
  294. X          int Omask;
  295. X
  296. X          /* Don't want to deal with signals in the middle of this */
  297. X              Omask = holdsigs();
  298. X
  299. X                    update_hincr;
  300. X            thishbp = HBLKPTR(((unsigned)sbrk(0))+HBLKSIZE-1 );
  301. X            heaplim = (char *) (((unsigned)thishbp) + size_to_get);
  302. X
  303. X            if( (brk(heaplim)) == ((char *)-1) ) {
  304. X                        write(2,"Out of Memory!  Giving up ...\n", 30);
  305. X            exit(-1);
  306. X            }
  307. X#                   ifdef PRINTSTATS
  308. X            printf("Need to increase heap size by %d\n",
  309. X                   size_to_get);
  310. X            fflush(stdout);
  311. X#                   endif
  312. X            heapsize += size_to_get;
  313. X            thishbp->hb_sz = 
  314. X            BYTES_TO_WORDS(size_to_get - sizeof(struct hblkhdr));
  315. X            freehblk(thishbp);
  316. X            /* Reenable signals */
  317. X              sigsetmask(Omask);
  318. X            hbp = savhbp;
  319. X            first_time = 1;
  320. X        continue;
  321. X        }
  322. X
  323. X        first_time = 0;
  324. X
  325. X        if( hbp == (struct hblk *)0 ) continue;
  326. X
  327. X        size_avail = hbp->hb_sz;
  328. X        if( size_avail >= size_needed ) {
  329. X        /* found a big enough block       */
  330. X        /* let thishbp --> the block      */
  331. X        /* set prevhbp, hbp to bracket it */
  332. X            thishbp = hbp;
  333. X            if( size_avail == size_needed ) {
  334. X            hbp = hbp->hb_next;
  335. X            uninit = thishbp -> hb_uninit;
  336. X            } else {
  337. X            uninit = thishbp -> hb_uninit;
  338. X            thishbp -> hb_uninit = 1; 
  339. X                /* Just in case we get interrupted by a */
  340. X                /* signal                               */
  341. X            hbp = (struct hblk *)
  342. X                (((unsigned)thishbp) + size_needed);
  343. X            hbp->hb_uninit = uninit;
  344. X            hbp->hb_next = thishbp->hb_next;
  345. X            hbp->hb_sz = size_avail - size_needed;
  346. X            }
  347. X        /* remove *thishbp from hblk freelist */
  348. X            if( prevhbp == (struct hblk *)0 ) {
  349. X            hblkfreelist = hbp;
  350. X            } else {
  351. X            prevhbp->hb_next = hbp;
  352. X            }
  353. X        /* save current list search position */
  354. X            savhbp = prevhbp;
  355. X        break;
  356. X        }
  357. X    }
  358. X
  359. X    /* set size and mask field of *thishbp correctly */
  360. X    thishbp->hb_sz = sz;
  361. X    thishbp->hb_mask = -1;  /* may be changed by new_hblk */
  362. X
  363. X    /* Clear block if necessary */
  364. X    if (uninit && sz > 0) {
  365. X        register word * p = &(thishbp -> hb_body[0]);
  366. X        register word * plim;
  367. X
  368. X        plim = (word *)(((char *)thishbp) + size_needed);
  369. X        while (p < plim) {
  370. X        *p++ = 0;
  371. X        }
  372. X    }
  373. X    /* Clear mark bits */
  374. X    {
  375. X        register word *p = (word *)(&(thishbp -> hb_marks[0]));
  376. X        register word * plim = (word *)(&(thishbp -> hb_marks[MARK_BITS_SZ]));
  377. X        while (p < plim) {
  378. X        *p++ = 0;
  379. X        }
  380. X    }
  381. X
  382. X#   ifdef DEBUG
  383. X    printf("Returning 0x%X\n", thishbp);
  384. X    fflush(stdout);
  385. X#   endif
  386. X    return( thishbp );
  387. X}
  388. X/* Clear the header information in a previously allocated heap block p */
  389. X/* so that it can be coalesced with an initialized heap block.         */
  390. Xstatic clear_header(p)
  391. Xregister struct hblk *p;
  392. X{
  393. X    p -> hb_sz = 0;
  394. X#   ifndef HBLK_MAP
  395. X      p -> hb_index = (struct hblk **)0;
  396. X#   endif
  397. X    p -> hb_next = 0;
  398. X    p -> hb_mask = 0;
  399. X#   if MARK_BITS_SZ <= 60
  400. X    /* Since this block was deallocated, only spurious mark      */
  401. X    /* bits corresponding to the header could conceivably be set */
  402. X    p -> hb_marks[0] = 0;
  403. X    p -> hb_marks[1] = 0;
  404. X#   else
  405. X    --> fix it
  406. X#   endif
  407. X}
  408. X
  409. X/*
  410. X * Free a heap block.
  411. X *
  412. X * Assume the block is not currently on hblklist.
  413. X *
  414. X * Coalesce the block with its neighbors if possible.
  415. X
  416. X * All mark words (except possibly the first) are assumed to be cleared.
  417. X * The body is assumed to be cleared unless hb_uninit is nonzero.
  418. X */
  419. Xvoid
  420. Xfreehblk(p)
  421. Xregister struct hblk *p;
  422. X{
  423. Xregister struct hblk *hbp, *prevhbp;
  424. Xregister int size;
  425. X
  426. X    /* savhbp may become invalid due to coalescing.  Clear it. */
  427. X    savhbp = (struct hblk *)0;
  428. X
  429. X    size = p->hb_sz;
  430. X    if( size < 0 ) size = -size;
  431. X    size = 
  432. X    ((WORDS_TO_BYTES(size)+sizeof(struct hblkhdr)+HBLKSIZE-1)
  433. X         & (~HBLKMASK));
  434. X    p->hb_sz = size;
  435. X
  436. X    prevhbp = (struct hblk *) 0;
  437. X    hbp = hblkfreelist;
  438. X
  439. X    while( (hbp != (struct hblk *)0) && (hbp < p) ) {
  440. X    prevhbp = hbp;
  441. X    hbp = hbp->hb_next;
  442. X    }
  443. X
  444. X    /* Coalesce with successor, if possible */
  445. X      if( (((unsigned)p)+size) == ((unsigned)hbp) ) {
  446. X    (p -> hb_uninit) |= (hbp -> hb_uninit);
  447. X    p->hb_next = hbp->hb_next;
  448. X    p->hb_sz += hbp->hb_sz;
  449. X    if (!p -> hb_uninit) clear_header(hbp);
  450. X      } else {
  451. X    p->hb_next = hbp;
  452. X      }
  453. X
  454. X    if( prevhbp == (struct hblk *)0 ) {
  455. X    hblkfreelist = p;
  456. X    } else if( (((unsigned)prevhbp) + prevhbp->hb_hdr.hbh_sz) ==
  457. X        ((unsigned)p) ) {
  458. X      /* Coalesce with predecessor */
  459. X    (prevhbp->hb_uninit) |= (p -> hb_uninit);
  460. X    prevhbp->hb_next = p->hb_next;
  461. X    prevhbp->hb_sz += p->hb_sz;
  462. X    if (!prevhbp -> hb_uninit) clear_header(p);
  463. X    } else {
  464. X    prevhbp->hb_next = p;
  465. X    }
  466. X}
  467. X
  468. X/* Add a heap block to hblklist or hblkmap.  */
  469. Xvoid add_hblklist(hbp)
  470. Xstruct hblk * hbp;
  471. X{
  472. X# ifdef HBLK_MAP
  473. X    long size = hbp->hb_sz;
  474. X    long index = divHBLKSZ(((long)hbp) - ((long)heapstart));
  475. X    long i;
  476. X
  477. X    if( size < 0 ) size = -size;
  478. X    size = (divHBLKSZ(WORDS_TO_BYTES(size)+sizeof(struct hblkhdr)+HBLKSIZE-1));
  479. X       /* in units of HBLKSIZE */
  480. X    hblkmap[index] = HBLK_VALID;
  481. X    for (i = 1; i < size; i++) {
  482. X    if (i < 0x7f) {
  483. X        hblkmap[index+i] = i;
  484. X    } else {
  485. X        /* May overflow a char.  Store largest possible value */
  486. X        hblkmap[index+i] = 0x7e;
  487. X    }
  488. X    }
  489. X# else
  490. X    if (last_hblk >= &hblklist[MAXHBLKS]) {
  491. X    fprintf(stderr, "Not configured for enough memory\n");
  492. X    exit(1);
  493. X    }
  494. X    *last_hblk = hbp;
  495. X    hbp -> hb_index = last_hblk;
  496. X    last_hblk++;
  497. X# endif
  498. X}
  499. X
  500. X/* Delete a heap block from hblklist or hblkmap.  */
  501. Xvoid del_hblklist(hbp)
  502. Xstruct hblk * hbp;
  503. X{
  504. X# ifdef HBLK_MAP
  505. X    long size = hbp->hb_sz;
  506. X    long index = divHBLKSZ(((long)hbp) - ((long)heapstart));
  507. X    long i;
  508. X
  509. X    if( size < 0 ) size = -size;
  510. X    size = (divHBLKSZ(WORDS_TO_BYTES(size)+sizeof(struct hblkhdr)+HBLKSIZE-1));
  511. X       /* in units of HBLKSIZE */
  512. X    for (i = 0; i < size; i++) {
  513. X    hblkmap[index+i] = HBLK_INVALID;
  514. X    }
  515. X# else
  516. X    register struct hblk ** list_entry;
  517. X    last_hblk--;
  518. X    /* Let **last_hblk use the slot previously occupied by *hbp */
  519. X    list_entry = hbp -> hb_index;
  520. X    (*last_hblk) -> hb_index = list_entry;
  521. X    *list_entry = *last_hblk;
  522. X# endif
  523. X}
  524. X
  525. X/* Initialize hblklist */
  526. Xvoid init_hblklist()
  527. X{
  528. X#   ifdef DEBUG
  529. X    printf("Here we are in init_hblklist - ");
  530. X    printf("last_hblk = %x\n",&(hblklist[0]));
  531. X#   endif
  532. X#   ifndef HBLK_MAP
  533. X      last_hblk = &(hblklist[0]);
  534. X#   endif
  535. X}
  536. /
  537. echo 'Extracting cons.c...'
  538. sed 's/^X//' > cons.c << '/'
  539. X/* Silly implementation of Lisp cons. Intentionally wastes lots of space */
  540. X/* to test collector.                                                    */
  541. X# include <stdio.h>
  542. X# include "cons.h"
  543. X
  544. Xint extra_count = 0;        /* Amount of space wasted in cons node */
  545. X
  546. Xsexpr cons (x, y)
  547. Xsexpr x;
  548. Xsexpr y;
  549. X{
  550. X    register sexpr r;
  551. X    register int i;
  552. X    register int *p;
  553. X    
  554. X    extra_count++;
  555. X    extra_count %= 3000;
  556. X    r = (sexpr) gc_malloc(8 + extra_count);
  557. X    for (p = (int *)r; ((char *)p) < ((char *)r) + extra_count + 8; p++) {
  558. X    if (*p) {
  559. X        fprintf(stderr, "Found nonzero at %X\n", p);
  560. X        abort(p);
  561. X        }
  562. X        *p = 13;
  563. X    }
  564. X    r -> sexpr_car = x;
  565. X    r -> sexpr_cdr = y;
  566. X    return(r);
  567. X}
  568. /
  569. echo 'Extracting cons.h...'
  570. sed 's/^X//' > cons.h << '/'
  571. Xstruct SEXPR {
  572. X    struct SEXPR * sexpr_car;
  573. X    struct SEXPR * sexpr_cdr;
  574. X};
  575. X
  576. Xtypedef struct SEXPR * sexpr;
  577. X
  578. Xextern sexpr cons();
  579. X
  580. X# define nil ((sexpr) 0)
  581. X# define car(x) ((x) -> sexpr_car)
  582. X# define cdr(x) ((x) -> sexpr_cdr)
  583. X# define null(x) ((x) == nil)
  584. X
  585. X# define head(x) car(x)
  586. X# define tail(x) cdr(x)
  587. X
  588. X# define caar(x) car(car(x))
  589. X# define cadr(x) car(cdr(x))
  590. X# define cddr(x) cdr(cdr(x))
  591. X# define cdar(x) cdr(car(x))
  592. X# define caddr(x) car(cdr(cdr(x)))
  593. X
  594. X# define first(x) car(x)
  595. X# define second(x) cadr(x)
  596. X# define third(x) caddr(x)
  597. X
  598. X# define list1(x) cons(x, nil)
  599. X# define list2(x,y) cons(x, cons(y, nil))
  600. X# define list3(x,y,z) cons(x, cons(y, cons(z, nil)))
  601. /
  602. echo 'Extracting mach_dep.c...'
  603. sed 's/^X//' > mach_dep.c << '/'
  604. X# include "runtime.h"
  605. X
  606. X/* Call allocobj or allocaobj after first saving at least those registers */
  607. X/* not preserved by the C compiler. The register used for return values   */
  608. X/* is not saved, since it will be clobbered anyway.                       */
  609. X# ifdef RT
  610. X    /* This is done in rt_allocobj.s */
  611. X# else
  612. Xasm("    .text");
  613. Xasm("    .globl  __allocobj");
  614. Xasm("    .globl  __allocaobj");
  615. Xasm("    .globl  _allocobj");
  616. Xasm("    .globl  _allocaobj");
  617. X
  618. X# ifdef M68K
  619. X    asm("_allocobj:");
  620. X    asm("   link    a6,#0");
  621. X    asm("    movl    d1,sp@-");
  622. X    asm("    movl    a0,sp@-");
  623. X    asm("    movl    a1,sp@-");
  624. X    asm("    movl    sp@(20),sp@-");
  625. X    asm("    jbsr    __allocobj");
  626. X    asm("    addl    #4,sp");
  627. X    asm("    movl    sp@+,a1");
  628. X    asm("    movl    sp@+,a0");
  629. X    asm("    movl    sp@+,d1");
  630. X    asm("    unlk    a6");
  631. X    asm("    rts");
  632. X    
  633. X    asm("_allocaobj:");
  634. X    asm("    link    a6,#0");
  635. X    asm("    movl    d1,sp@-");
  636. X    asm("    movl    a0,sp@-");
  637. X    asm("    movl    a1,sp@-");
  638. X    asm("    movl    sp@(20),sp@-");
  639. X    asm("    jbsr    __allocaobj");
  640. X    asm("    addl    #4,sp");
  641. X    asm("    movl    sp@+,a1");
  642. X    asm("    movl    sp@+,a0");
  643. X    asm("    movl    sp@+,d1");
  644. X    asm("    unlk    a6");
  645. X    asm("    rts");
  646. X# endif
  647. X
  648. X# ifdef I386
  649. X    asm(".data");
  650. X    asm("gc_ret_value: .word 0");
  651. X    asm(".word 0");
  652. X    asm(".text");
  653. X
  654. X    asm("_allocaobj:");
  655. X    asm("pushl %ebp");
  656. X    asm("movl %esp,%ebp");
  657. X    asm("pushal");
  658. X    asm("pushl 8(%ebp)");          /* Push orignal argument */
  659. X    asm("call __allocaobj");
  660. X    asm("popl %ecx");
  661. X    asm("movl %eax,gc_ret_value");  /* Save return value */
  662. X    asm("popal");
  663. X    asm("movl gc_ret_value,%eax");
  664. X    asm("leave");
  665. X    asm("ret");
  666. X
  667. X    asm("_allocobj:");
  668. X    asm("pushl %ebp");
  669. X    asm("movl %esp,%ebp");
  670. X    asm("pushal");
  671. X    asm("pushl 8(%ebp)");          /* Push orignal argument */
  672. X    asm("call __allocobj");
  673. X    asm("popl %ecx");
  674. X    asm("movl %eax,gc_ret_value");  /* Save return value */
  675. X    asm("popal");
  676. X    asm("movl gc_ret_value,%eax");
  677. X    asm("leave");
  678. X    asm("ret");
  679. X# endif
  680. X
  681. X# ifdef SPARC
  682. X    asm("_allocaobj:");
  683. X    asm("    ba    __allocaobj");
  684. X    asm("    nop");
  685. X    asm("_allocobj:");
  686. X    asm("    ba    __allocobj");
  687. X    asm("    nop");
  688. X    
  689. X#   include <sun4/trap.h>
  690. X    asm("    .globl    _save_regs_in_stack");
  691. X    asm("_save_regs_in_stack:");
  692. X    asm("    t    0x3   ! ST_FLUSH_WINDOWS");
  693. X    asm("    mov    %sp,%o0");
  694. X    asm("    retl");
  695. X    asm("    nop");
  696. X# endif
  697. X
  698. X# ifdef VAX
  699. X    asm("_allocobj:");
  700. X    asm(".word    0x3e");
  701. X    asm("pushl   4(ap)");
  702. X    asm("calls   $1,__allocobj");
  703. X    asm("ret");
  704. X    asm("_allocaobj:");
  705. X    asm(".word   0x3e");
  706. X    asm("pushl   4(ap)");
  707. X    asm("calls   $1,__allocaobj");
  708. X    asm("ret");
  709. X# endif
  710. X
  711. X# ifdef NS32K
  712. X    asm("_allocobj:");
  713. X    asm("enter [],$0");
  714. X    asm("movd r1,tos");
  715. X    asm("movd r2,tos");
  716. X    asm("movd 8(fp),tos");
  717. X    asm("bsr ?__allocobj");
  718. X    asm("adjspb $-4");
  719. X    asm("movd tos,r2");
  720. X    asm("movd tos,r1");
  721. X    asm("exit []");
  722. X    asm("ret $0");
  723. X    asm("_allocaobj:");
  724. X    asm("enter [],$0");
  725. X    asm("movd r1,tos");
  726. X    asm("movd r2,tos");
  727. X    asm("movd 8(fp),tos");
  728. X    asm("bsr ?__allocaobj");
  729. X    asm("adjspb $-4");
  730. X    asm("movd tos,r2");
  731. X    asm("movd tos,r1");
  732. X    asm("exit []");
  733. X    asm("ret $0");
  734. X# endif
  735. X
  736. X
  737. X# if !defined(VAX) && !defined(M68K) && !defined(SPARC) && !defined(I386) && !defined(NS32K)
  738. X    --> fix it
  739. X# endif
  740. X
  741. X# endif
  742. X
  743. X/* Routine to mark from registers that are preserved by the C compiler */
  744. Xmark_regs()
  745. X{
  746. X#       ifdef RT
  747. X      register long TMP_SP; /* must be bound to r11 */
  748. X#       endif
  749. X#       ifdef VAX
  750. X      /* r1 through r5 are preserved by allocobj, and therefore     */
  751. X      /* on the stack.                                              */
  752. X      asm("pushl r11");     asm("calls $1,_tl_mark");
  753. X      asm("pushl r10");     asm("calls $1,_tl_mark");
  754. X      asm("pushl r9");    asm("calls $1,_tl_mark");
  755. X      asm("pushl r8");    asm("calls $1,_tl_mark");
  756. X      asm("pushl r7");    asm("calls $1,_tl_mark");
  757. X      asm("pushl r6");    asm("calls $1,_tl_mark");
  758. X
  759. X      asm("movl sp,r11");        /* TMP_SP = stack pointer sp    */
  760. X#       endif
  761. X#       ifdef M68K
  762. X      /* a0, a1 and d1 are preserved by allocobj */
  763. X      /*  and therefore are on stack             */
  764. X    
  765. X      asm("subqw #0x4,sp");        /* allocate word on top of stack */
  766. X
  767. X      asm("movl a0,sp@");    asm("jbsr _tl_mark");
  768. X      asm("movl a1,sp@");    asm("jbsr _tl_mark");
  769. X      asm("movl a2,sp@");    asm("jbsr _tl_mark");
  770. X      asm("movl a3,sp@");    asm("jbsr _tl_mark");
  771. X      asm("movl a4,sp@");    asm("jbsr _tl_mark");
  772. X      asm("movl a5,sp@");    asm("jbsr _tl_mark");
  773. X      /* Skip frame pointer and stack pointer */
  774. X      asm("movl d0,sp@");    asm("jbsr _tl_mark");
  775. X      asm("movl d1,sp@");    asm("jbsr _tl_mark");
  776. X      asm("movl d2,sp@");    asm("jbsr _tl_mark");
  777. X      asm("movl d3,sp@");    asm("jbsr _tl_mark");
  778. X      asm("movl d4,sp@");    asm("jbsr _tl_mark");
  779. X      asm("movl d5,sp@");    asm("jbsr _tl_mark");
  780. X      asm("movl d6,sp@");    asm("jbsr _tl_mark");
  781. X      asm("movl d7,sp@");    asm("jbsr _tl_mark");
  782. X
  783. X      asm("addqw #0x4,sp");        /* put stack back where it was    */
  784. X
  785. X      asm("movl a7,d7");        /* TMP_SP = stack pointer a7    */
  786. X#       endif
  787. X
  788. X#       ifdef I386
  789. X      asm("pushl %eax");  asm("call _tl_mark"); asm("addl $4,%esp");
  790. X      asm("pushl %ecx");  asm("call _tl_mark"); asm("addl $4,%esp");
  791. X      asm("pushl %edx");  asm("call _tl_mark"); asm("addl $4,%esp");
  792. X      asm("pushl %esi");  asm("call _tl_mark"); asm("addl $4,%esp");
  793. X      asm("pushl %edi");  asm("call _tl_mark"); asm("addl $4,%esp");
  794. X      asm("pushl %ebx");  asm("call _tl_mark"); asm("addl $4,%esp");
  795. X#       endif
  796. X
  797. X#       ifdef NS32K
  798. X      asm ("movd r3, tos"); asm ("bsr ?_tl_mark"); asm ("adjspb $-4");
  799. X      asm ("movd r4, tos"); asm ("bsr ?_tl_mark"); asm ("adjspb $-4");
  800. X      asm ("movd r5, tos"); asm ("bsr ?_tl_mark"); asm ("adjspb $-4");
  801. X      asm ("movd r6, tos"); asm ("bsr ?_tl_mark"); asm ("adjspb $-4");
  802. X      asm ("movd r7, tos"); asm ("bsr ?_tl_mark"); asm ("adjspb $-4");
  803. X#       endif
  804. X
  805. X#       ifdef SPARC
  806. X      save_regs_in_stack();
  807. X#       endif
  808. X
  809. X#    ifdef RT
  810. X      /* we used to think this wasn't necessary, but gcollect */
  811. X      /* can be called from many places ...                   */
  812. X        tl_mark(TMP_SP);    /* tl_mark from r11 */
  813. X
  814. X        asm("cas r11, r6, r0"); tl_mark(TMP_SP);    /* r6 */
  815. X        asm("cas r11, r7, r0"); tl_mark(TMP_SP);    /* through */
  816. X        asm("cas r11, r8, r0"); tl_mark(TMP_SP);    /* r10 */
  817. X        asm("cas r11, r9, r0"); tl_mark(TMP_SP);
  818. X        asm("cas r11, r10, r0"); tl_mark(TMP_SP);
  819. X
  820. X        asm("cas r11, r12, r0"); tl_mark(TMP_SP); /* r12 */
  821. X        asm("cas r11, r13, r0"); tl_mark(TMP_SP); /* through */
  822. X        asm("cas r11, r14, r0"); tl_mark(TMP_SP); /* r15 */
  823. X        asm("cas r11, r15, r0"); tl_mark(TMP_SP);
  824. X#    endif
  825. X
  826. X      /* other machines... */
  827. X#       if !(defined M68K) && !(defined VAX) && !(defined RT) && !(defined SPARC) && !(defined I386) &&!(defined NS32K)
  828. X        --> bad news <--
  829. X#       endif
  830. X}
  831. /
  832. echo 'Extracting mips_mach_dep.s...'
  833. sed 's/^X//' > mips_mach_dep.s << '/'
  834. X# define call_mark(x)     move    $4,x;    jal     tl_mark
  835. X
  836. X # Mark from machine registers that are saved by C compiler
  837. X    .globl  mark_regs
  838. X    .ent    mark_regs
  839. Xmark_regs:
  840. X    subu    $sp,4       ## Need to save only return address
  841. X    sw      $31,4($sp)
  842. X    .mask   0x80000000,0
  843. X    .frame  $sp,4,$31
  844. X    call_mark($2)
  845. X    call_mark($3)
  846. X    call_mark($16)
  847. X    call_mark($17)
  848. X    call_mark($18)
  849. X    call_mark($19)
  850. X    call_mark($20)
  851. X    call_mark($21)
  852. X    call_mark($22)
  853. X    call_mark($23)
  854. X    call_mark($30)
  855. X    lw      $31,4($sp)
  856. X    addu    $sp,4
  857. X    j       $31
  858. X    .end    mark_regs
  859. X
  860. X    .globl  allocobj
  861. X    .ent    allocobj
  862. Xallocobj:
  863. X    subu    $sp,68
  864. X    sw      $31,68($sp)
  865. X    sw      $25,64($sp)
  866. X    sw      $24,60($sp)
  867. X    sw      $15,56($sp)
  868. X    sw      $14,52($sp)
  869. X    sw      $13,48($sp)
  870. X    sw      $12,44($sp)
  871. X    sw      $11,40($sp)
  872. X    sw      $10,36($sp)
  873. X    sw      $9,32($sp)
  874. X    sw      $8,28($sp)
  875. X    sw      $7,24($sp)
  876. X    sw      $6,20($sp)
  877. X    sw      $5,16($sp)
  878. X    sw      $4,12($sp)
  879. X    sw      $3,8($sp)
  880. X    .set    noat
  881. X    sw      $at,4($sp)
  882. X    .set    at
  883. X    .mask   0x8300fffa,0
  884. X    .frame  $sp,68,$31
  885. X    jal     _allocobj
  886. X    lw      $31,68($sp)
  887. X    lw      $25,64($sp)
  888. X    lw      $24,60($sp)
  889. X    lw      $15,56($sp)
  890. X    lw      $14,52($sp)
  891. X    lw      $13,48($sp)
  892. X    lw      $12,44($sp)
  893. X    lw      $11,40($sp)
  894. X    lw      $10,36($sp)
  895. X    lw      $9,32($sp)
  896. X    lw      $8,28($sp)
  897. X    lw      $7,24($sp)
  898. X    lw      $6,20($sp)
  899. X    lw      $5,16($sp)
  900. X    lw      $4,12($sp)
  901. X    lw      $3,8($sp)
  902. X #  don't restore $2, since it's the return value
  903. X    .set    noat
  904. X    lw      $at,4($sp)
  905. X    .set    at
  906. X    addu    $sp,68
  907. X    j       $31
  908. X    .end    allocobj
  909. X
  910. X    .globl  allocaobj
  911. X    .ent    allocaobj
  912. Xallocaobj:
  913. X    subu    $sp,68
  914. X    sw      $31,68($sp)
  915. X    sw      $25,64($sp)
  916. X    sw      $24,60($sp)
  917. X    sw      $15,56($sp)
  918. X    sw      $14,52($sp)
  919. X    sw      $13,48($sp)
  920. X    sw      $12,44($sp)
  921. X    sw      $11,40($sp)
  922. X    sw      $10,36($sp)
  923. X    sw      $9,32($sp)
  924. X    sw      $8,28($sp)
  925. X    sw      $7,24($sp)
  926. X    sw      $6,20($sp)
  927. X    sw      $5,16($sp)
  928. X    sw      $4,12($sp)
  929. X    sw      $3,8($sp)
  930. X    .set    noat
  931. X    sw      $at,4($sp)
  932. X    .set    at
  933. X    .mask   0x8300fffa,0
  934. X    .frame  $sp,68,$31
  935. X    jal     _allocaobj
  936. X    lw      $31,68($sp)
  937. X    lw      $25,64($sp)
  938. X    lw      $24,60($sp)
  939. X    lw      $15,56($sp)
  940. X    lw      $14,52($sp)
  941. X    lw      $13,48($sp)
  942. X    lw      $12,44($sp)
  943. X    lw      $11,40($sp)
  944. X    lw      $10,36($sp)
  945. X    lw      $9,32($sp)
  946. X    lw      $8,28($sp)
  947. X    lw      $7,24($sp)
  948. X    lw      $6,20($sp)
  949. X    lw      $5,16($sp)
  950. X    lw      $4,12($sp)
  951. X    lw      $3,8($sp)
  952. X #  don't restore $2, since it's the return value
  953. X    .set    noat
  954. X    lw      $at,4($sp)
  955. X    .set    at
  956. X    addu    $sp,68
  957. X    j       $31
  958. X    .end    allocaobj
  959. /
  960. echo 'Extracting reclaim.c...'
  961. sed 's/^X//' > reclaim.c << '/'
  962. X#include <stdio.h>
  963. X#include "runtime.h"
  964. X#define DEBUG
  965. X#undef DEBUG
  966. X#ifdef PRINTSTATS
  967. X#  define GATHERSTATS
  968. X#endif
  969. X
  970. Xlong mem_found = 0;     /* Number of longwords of memory reclaimed     */
  971. X
  972. Xlong composite_in_use;  /* Number of longwords in accessible composite */
  973. X            /* objects.                                    */
  974. X
  975. Xlong atomic_in_use;     /* Number of longwords in accessible atomic */
  976. X            /* objects.                                 */
  977. X
  978. X/*
  979. X * reclaim phase
  980. X *
  981. X */
  982. X
  983. Xreclaim()
  984. X{
  985. Xregister struct hblk *hbp;    /* ptr to current heap block        */
  986. Xregister int word_no;        /* Number of word in block        */
  987. Xregister long i;
  988. Xregister word *p;        /* pointer to current word in block    */
  989. Xregister int mb;        /* mark bit of current word        */
  990. Xint sz;                /* size of objects in current block    */
  991. Xword *plim;
  992. Xstruct hblk **nexthbp;        /* ptr to ptr to current heap block    */
  993. Xint nonempty;            /* nonempty ^ done with block => block empty*/
  994. Xstruct obj *list;        /* used to build list of free words in block*/
  995. Xregister int is_atomic;         /* => current block contains atomic objs */
  996. X
  997. X#   ifdef DEBUG
  998. X        printf("clearing all between %x and %x, %x and %x\n",
  999. X               objfreelist, &objfreelist[MAXOBJSZ+1],
  1000. X               aobjfreelist,&aobjfreelist[MAXAOBJSZ+1]);
  1001. X#   endif
  1002. X    { register struct obj **fop;
  1003. X    for( fop = objfreelist; fop < &objfreelist[MAXOBJSZ+1]; fop++ ) {
  1004. X        *fop = (struct obj *)0;
  1005. X    }
  1006. X    for( fop = aobjfreelist; fop < &aobjfreelist[MAXAOBJSZ+1]; fop++ ) {
  1007. X        *fop = (struct obj *)0;
  1008. X    }
  1009. X    }
  1010. X    
  1011. X    atomic_in_use = 0;
  1012. X    composite_in_use = 0;
  1013. X
  1014. X#   ifdef PRINTBLOCKS
  1015. X        printf("reclaim: current block sizes:\n");
  1016. X#   endif
  1017. X
  1018. X  /* go through all heap blocks (in hblklist) and reclaim unmarked objects */
  1019. X# ifdef HBLK_MAP
  1020. X    hbp = (struct hblk *) heapstart;
  1021. X    for (; ((char *)hbp) < heaplim; hbp++) if (is_hblk(hbp)) {
  1022. X/* fprintf(stderr, "Reclaiming in 0x%X\n", hbp); */
  1023. X# else
  1024. X    nexthbp = hblklist;
  1025. X    while( nexthbp < last_hblk ) {
  1026. X    hbp = *nexthbp++;
  1027. X# endif
  1028. X
  1029. X    nonempty = FALSE;
  1030. X    sz = hbp -> hb_sz;
  1031. X    is_atomic = 0;
  1032. X    if (sz < 0) {
  1033. X        sz = -sz;
  1034. X        is_atomic = 1;        /* this block contains atomic objs */
  1035. X    }
  1036. X#    ifdef PRINTBLOCKS
  1037. X            printf("%d(%c",sz, (is_atomic)? 'a' : 'c');
  1038. X#    endif
  1039. X
  1040. X    if( sz > (is_atomic? MAXAOBJSZ : MAXOBJSZ) ) {  /* 1 big object */
  1041. X        mb = mark_bit(hbp, (hbp -> hb_body) - ((word *)(hbp)));
  1042. X        if( mb ) {
  1043. X#               ifdef GATHERSTATS
  1044. X            if (is_atomic) {
  1045. X            atomic_in_use += sz;
  1046. X            } else {
  1047. X            composite_in_use += sz;
  1048. X            }
  1049. X#               endif
  1050. X        nonempty = TRUE;
  1051. X        } else {
  1052. X        mem_found += sz;
  1053. X        }
  1054. X    } else {                /* group of smaller objects */
  1055. X        p = (word *)(hbp->hb_body);
  1056. X        word_no = ((word *)p) - ((word *)hbp);
  1057. X        plim = (word *)((((unsigned)hbp) + HBLKSIZE)
  1058. X               - WORDS_TO_BYTES(sz));
  1059. X
  1060. X        list = (is_atomic) ? aobjfreelist[sz] : objfreelist[sz];
  1061. X
  1062. X      /* go through all words in block */
  1063. X        while( p <= plim )  {
  1064. X        mb = mark_bit(hbp, word_no);
  1065. X
  1066. X        if( mb ) {
  1067. X#                   ifdef GATHERSTATS
  1068. X            if (is_atomic) atomic_in_use += sz;
  1069. X            else           composite_in_use += sz;
  1070. X#                   endif
  1071. X#                   ifdef DEBUG
  1072. X                        printf("found a reachable obj\n");
  1073. X#            endif
  1074. X            nonempty = TRUE;
  1075. X            p += sz;
  1076. X        } else {
  1077. X          mem_found += sz;
  1078. X          /* word is available - put on list */
  1079. X            ((struct obj *)p)->obj_link = list;
  1080. X            list = ((struct obj *)p);
  1081. X          if (is_atomic) {
  1082. X            p += sz;
  1083. X          } else {
  1084. X            /* Clear object, advance p to next object in the process */
  1085. X            i = (long)(p + sz);
  1086. X                        p++; /* Skip link field */
  1087. X                        while (p < (word *)i) {
  1088. X                *p++ = 0;
  1089. X            }
  1090. X          }
  1091. X        }
  1092. X        word_no += sz;
  1093. X        }
  1094. X
  1095. X      /*
  1096. X       * if block has reachable words in it, we can't reclaim the
  1097. X       * whole thing so put list of free words in block back on
  1098. X       * free list for this size.
  1099. X       */
  1100. X        if( nonempty ) {
  1101. X        if ( is_atomic )    aobjfreelist[sz] = list;
  1102. X        else            objfreelist[sz] = list;
  1103. X        }
  1104. X    } 
  1105. X
  1106. X#    ifdef PRINTBLOCKS
  1107. X            printf("%c),", nonempty ? 'n' : 'e' );
  1108. X#    endif
  1109. X    if (!nonempty) {
  1110. X            if (!is_atomic && sz <= MAXOBJSZ) {
  1111. X                /* Clear words at beginning of objects */
  1112. X                /* Since most of it is already cleared */
  1113. X          p = (word *)(hbp->hb_body);
  1114. X          plim = (word *)((((unsigned)hbp) + HBLKSIZE)
  1115. X             - WORDS_TO_BYTES(sz));
  1116. X          while (p <= plim) {
  1117. X            *p = 0;
  1118. X            p += sz;
  1119. X          }
  1120. X        hbp -> hb_uninit = 0;
  1121. X        } else {
  1122. X        /* Mark it as being uninitialized */
  1123. X        hbp -> hb_uninit = 1;
  1124. X        }
  1125. X
  1126. X      /* remove this block from list of active blocks */
  1127. X        del_hblklist(hbp);    
  1128. X
  1129. X#           ifndef HBLKMAP
  1130. X          /* This entry in hblklist just got replaced; look at it again  */
  1131. X          /* This admittedly depends on the internals of del_hblklist... */
  1132. X          nexthbp--;
  1133. X#           endif
  1134. X
  1135. X        freehblk(hbp);
  1136. X    }  /* end if (one big object...) */
  1137. X    } /* end while (nexthbp ...) */
  1138. X
  1139. X#   ifdef PRINTBLOCKS
  1140. X        printf("\n");
  1141. X#   endif
  1142. X}
  1143. /
  1144. echo 'Extracting rt_allocobj.s...'
  1145. sed 's/^X//' > rt_allocobj.s << '/'
  1146. X/*
  1147. X * This (assembly) file contains the functions:
  1148. X *    struct obj * allocobj(sz)
  1149. X *    struct obj * allocaobj(sz)
  1150. X */
  1151. X
  1152. X
  1153. X/*
  1154. X * allocobj(i) insures that the free list entry for objects of size
  1155. X * i is not empty.
  1156. X *
  1157. X * Call _allocobj after first saving the registers which
  1158. X * are not guaranteed to be preserved (r0-r5 and r15).
  1159. X *
  1160. X * Note: the reason we have to use this interface between the caller
  1161. X * and the garbage collector is in order to preserve the caller's registers
  1162. X * which the C compiler would normally trash.  We just stick 'em on the stack
  1163. X * so that the mark_all procedure (which marks everything on the stack) will
  1164. X * see them.
  1165. X *
  1166. X * this is the RT version. The 68k version is in 68Kallocobj.s
  1167. X */
  1168. X
  1169. X/* this prolog was copied from a cc-produced .s file */
  1170. X    .text
  1171. X    .align 2
  1172. X    .data
  1173. X    .align 2
  1174. X    .ltorg
  1175. X    .text
  1176. X    .ascii "<allocobj>"
  1177. X    .align 2
  1178. X    .globl _.allocobj
  1179. X_.allocobj:
  1180. X    .data
  1181. X    .globl _allocobj
  1182. X_allocobj: .long _.allocobj    /* text area contains instr ptr    */
  1183. X    .text
  1184. X    /*
  1185. X     * save registers which will be trashed on the stack in the place
  1186. X     * the RT linkage convention uses for saving registers
  1187. X     */
  1188. X    .using    _allocobj,r14    /* tell assembler r14 is reliable base */
  1189. X    stm    r3, -100+(3*4)(r1)    /* we don't save r1 cause it's sp */
  1190. X    ai    r1,r1,-(36+13*4)
  1191. X    mr    r14, r0        /* initialize data area pointer */
  1192. X
  1193. X    balix    r15, _._allocobj    /* call _allocobj()    */
  1194. X    get    r0,$.long(__allocobj)    /* get data area pointer */
  1195. X
  1196. X    lm    r3, -100+(36+13*4)+(3*4)(r1)    /* restore regs */
  1197. X    brx    r15        /* return to caller (no restore req'd)    */
  1198. X    ai    r1, $(36+13*4)    /* restore r1 to where it belongs */
  1199. X
  1200. X/* trace table for allocobj */
  1201. X    .align 2
  1202. X    .byte    0xdf        /* magic1 */
  1203. X    .byte    0x07        /* code */
  1204. X    .byte    0xdf        /* magic2 */
  1205. X    .byte    0x08        /* first_gpr << 4 | opt stuff */
  1206. X    .byte    0x01        /* no. args and stack reg num    */
  1207. X    .byte    0x3c        /* 0011 1100 ==> stack frame sz = 60    */
  1208. X    .data
  1209. X    .ltorg
  1210. X
  1211. X    .text
  1212. X    .ascii "<allocaobj>"
  1213. X    .align 2
  1214. X    .globl _.allocaobj
  1215. X_.allocaobj:
  1216. X    .data
  1217. X    .globl _allocaobj
  1218. X_allocaobj: .long _.allocaobj    /* text area contains instr ptr    */
  1219. X    .text
  1220. X    /*
  1221. X     * save registers which will be trashed on the stack in the place
  1222. X     * the RT linkage convention uses for saving registers
  1223. X     */
  1224. X    .using    _allocaobj,r14    /* tell assembler r14 is reliable base */
  1225. X    stm    r3, -100+(3*4)(r1)    /* we don't save r1 cause it's sp */
  1226. X    ai    r1,r1,-(36+13*4)
  1227. X    mr    r14, r0        /* initialize data area pointer */
  1228. X
  1229. X    balix    r15, _._allocaobj    /* call _allocaobj()    */
  1230. X    get    r0,$.long(__allocaobj)    /* get data area pointer */
  1231. X
  1232. X    lm    r3, -100+(36+13*4)+(3*4)(r1)    /* restore regs */
  1233. X    brx    r15        /* return to caller (no restore req'd)    */
  1234. X    ai    r1, $(36+13*4)    /* restore r1 to where it belongs */
  1235. X
  1236. X/* trace table for allocaobj */
  1237. X    .align 2
  1238. X    .byte    0xdf        /* magic1 */
  1239. X    .byte    0x07        /* code */
  1240. X    .byte    0xdf        /* magic2 */
  1241. X    .byte    0x08        /* first_gpr << 4 | opt stuff */
  1242. X    .byte    0x01        /* no. args and stack reg num    */
  1243. X    .byte    0x3c        /* 0011 1100 ==> stack frame sz = 60    */
  1244. X    .data
  1245. X    .ltorg
  1246. X
  1247. X
  1248. X.globl .oVpcc
  1249. X.globl .oVncs
  1250. X.set .oVpcc, 0
  1251. X.set .oVncs, 0
  1252. /
  1253. echo 'Extracting test.c...'
  1254. sed 's/^X//' > test.c << '/'
  1255. X/* Somewhat nonconvincing test for garbage collector.                */
  1256. X/* Note that this intentionally uses the worlds worst implementation */
  1257. X/* of cons.  It eats up gobs of memory in an attempt to break the    */
  1258. X/* collector.  Process size should grow to about 1.5 Meg and stay    */
  1259. X/* there.                                                            */
  1260. X/* Should take about 25 seconds (2 minutes) to run on a              */
  1261. X/* Sun 3/60 (Vax 11/750)                                             */
  1262. X/* (The Vax does reasonably well here because the compiler assures   */
  1263. X/* longword pointer alignment.)                                      */
  1264. X
  1265. X# include <stdio.h>
  1266. X# include "cons.h"
  1267. X
  1268. X/* Return reverse(x) concatenated with y */
  1269. Xsexpr reverse1(x, y)
  1270. Xsexpr x, y;
  1271. X{
  1272. X    if (null(x)) {
  1273. X        return(y);
  1274. X    } else {
  1275. X        return( reverse1(cdr(x), cons(car(x), y)) );
  1276. X    }
  1277. X}
  1278. X
  1279. Xsexpr reverse(x)
  1280. Xsexpr x;
  1281. X{
  1282. X    return( reverse1(x, nil) );
  1283. X}
  1284. X
  1285. Xsexpr ints(low, up)
  1286. Xint low, up;
  1287. X{
  1288. X    if (low > up) {
  1289. X    return(nil);
  1290. X    } else {
  1291. X        return(cons(low, ints(low+1, up)));
  1292. X    }
  1293. X}
  1294. X
  1295. Xvoid print_int_list(x)
  1296. Xsexpr x;
  1297. X{
  1298. X    if (null(x)) {
  1299. X        printf("NIL\n");
  1300. X    } else {
  1301. X        printf("%d", car(x));
  1302. X        if (!null(cdr(x))) {
  1303. X            printf(", ");
  1304. X            print_int_list(cdr(x));
  1305. X        } else {
  1306. X            printf("\n");
  1307. X        }
  1308. X    }
  1309. X}
  1310. X
  1311. X/* Try to force a to be strangely aligned */
  1312. Xstruct {
  1313. X  char dummy;
  1314. X  sexpr aa;
  1315. X} A;
  1316. X#define a A.aa
  1317. X
  1318. Xmain()
  1319. X{
  1320. X    int i;
  1321. X    sexpr b;
  1322. X
  1323. X    gc_init();
  1324. X    a = ints(1, 100);
  1325. X    b = ints(1, 50);
  1326. X    print_int_list(a);
  1327. X    print_int_list(b);
  1328. X    print_int_list(reverse(a));
  1329. X    print_int_list(reverse(b));
  1330. X    for (i = 0; i < 100; i++) {
  1331. X        b = reverse(reverse(b));
  1332. X    }
  1333. X    print_int_list(a);
  1334. X    print_int_list(b);
  1335. X    print_int_list(reverse(a));
  1336. X    print_int_list(reverse(b));
  1337. X}
  1338. X
  1339. /
  1340. echo 'Distribution file ../gc.shar.02 complete.'
  1341.  
  1342.