home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume20 / c-gc / part01 next >
Encoding:
Internet Message Format  |  1989-09-17  |  51.4 KB

  1. Subject:  v20i002:  C memory garbage collector, Part01/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 2
  8. Archive-name: c-gc/part01
  9.  
  10. This is intended to be a general purpose, garbage collecting storage
  11. allocator.  The algorithms used are described in:
  12.     Boehm, H., and M. Weiser,
  13.     "Garbage Collection in an Uncooperative Environment",
  14.     Software Practice & Experience, September 1988, pp.  807-820.
  15.  
  16. Many of the ideas underlying the collector have previously been explored
  17. by others.  (We discovered recently that Doug McIlroy wrote a more or less
  18. similar collector that is part of version 8 UNIX (tm).)  However none of
  19. this work appears to have been widely disseminated.
  20.  
  21. The tools for detecting storage leaks described in the above paper are not
  22. included here.  There is some hope that they might be released by Xerox in
  23. the future.
  24.  
  25. Since the collector does not require pointers to be tagged, it does not
  26. attempt to insure that all inaccessible storage is reclaimed.  However,
  27. in our experience, it is typically more successful at reclaiming unused
  28. memory than most C programs using explicit deallocation.
  29.  
  30. echo 'Start of distribution file ../gc.shar.01:'
  31. echo 'Extracting Makefile...'
  32. sed 's/^X//' > Makefile << '/'
  33. XOBJS= reclaim.o allochblk.o misc.o alloc.o mach_dep.o
  34. X# add rt_allocobj.o for RT version
  35. X
  36. XSRCS= reclaim.c allochblk.c misc.c alloc.c mach_dep.c rt_allocobj.s mips_mach_dep.s
  37. X
  38. XCFLAGS= -O
  39. X
  40. X# Set SPECIALFLAGS to -q nodirect_code on Encore.
  41. X
  42. XSPECIALCFLAGS = 
  43. X
  44. Xall: gc.o test
  45. X
  46. X$(OBJS): runtime.h
  47. X
  48. Xgc.a: $(OBJS)
  49. X    ar ru gc.a $(OBJS)
  50. X    ranlib gc.a
  51. X
  52. Xgc.o: $(OBJS)
  53. X    -ld -r -o gc.o $(OBJS)
  54. X
  55. X# mach_dep.c doesn't like optimization
  56. X# On a MIPS machine, move mips_mach_dep.s to mach_dep.s and remove
  57. X# the following two lines from this Makefile
  58. X# On an RT, it is a good idea to force mach_dep.c to be compiled with pcc.
  59. Xmach_dep.o: mach_dep.c
  60. X    cc -c ${SPECIALCFLAGS} mach_dep.c
  61. X
  62. Xclean: 
  63. X    rm -f test gc.o gc.a test.o cons.o $(OBJS)
  64. X
  65. Xtest.o: cons.h test.c
  66. X
  67. Xcons.o: cons.h cons.c
  68. X
  69. Xtest: test.o cons.o gc.o
  70. X    cc -o test test.o cons.o gc.o
  71. X# Some version of the RT ld command require that gc.o on the preceding lines
  72. X# be changed to gc.a
  73. X
  74. Xshar:
  75. X    makescript -o gc.shar README Makefile runtime.h ${SRCS} test.c cons.c cons.h
  76. /
  77. echo 'Extracting alloc.c...'
  78. sed 's/^X//' > alloc.c << '/'
  79. X/*
  80. X * This file contains the functions:
  81. X *    void new_hblk(n)
  82. X *    static void clear_marks()
  83. X *    tl_mark(p)
  84. X *    mark()
  85. X *    mark_all(b,t)
  86. X *    void gcollect()
  87. X *    expand_hp: func[val Short] val Void
  88. X *    struct obj * _allocobj(sz)
  89. X *    struct obj * _allocaobj(sz)
  90. X *
  91. X * And the global variables:
  92. X *    struct obj * objfreelist[MAXOBJSZ+1];
  93. X *    struct obj * aobjfreelist[MAXOBJSZ+1];
  94. X *    word * mark_stack_bottom;
  95. X *    word * mark_stack_top;
  96. X */
  97. X
  98. X
  99. X# include <stdio.h>
  100. X# include <signal.h>
  101. X# include <sys/types.h>
  102. X# include <sys/times.h>
  103. X# include "runtime.h"
  104. X
  105. X/* Leaving these defined enables output to stderr.  In order of */
  106. X/* increasing verbosity:                                        */
  107. X#define REPORT_FAILURE   /* Print values that looked "almost" like pointers */
  108. X#undef REPORT_FAILURE
  109. X#define DEBUG            /* Verbose debugging output */
  110. X#undef DEBUG
  111. X#define DEBUG2           /* EXTREMELY verbose debugging output */
  112. X#undef DEBUG2
  113. X#define USE_STACK       /* Put mark stack onto process stack.  This assumes */
  114. X            /* that it's safe to put data below the stack ptr,  */
  115. X            /* and that the system will expand the stack as     */
  116. X            /* necessary.  This is known to be true under Sun   */
  117. X            /* UNIX (tm) and Vax Berkeley UNIX.  It is also     */
  118. X            /* known to be false under some other UNIX          */
  119. X            /* implementations.                                 */
  120. X#undef USE_HEAP
  121. X#ifdef RT
  122. X#   define USE_HEAP
  123. X#   undef USE_STACK
  124. X#endif
  125. X#ifdef MIPS
  126. X#   define USE_HEAP
  127. X#   undef USE_STACK
  128. X#endif
  129. X
  130. X/*
  131. X * This is an attempt at a garbage collecting storage allocator
  132. X * on a Motorola 68000 series or an a Vax.  The garbage
  133. X * collector is overly conservative in that it may fail to reclaim
  134. X * inaccessible storage.  On the other hand, it does not assume
  135. X * any runtime tag information.
  136. X * We make the following assumptions:
  137. X *  1.  We are running under something that looks like Berkeley UNIX,
  138. X *      on one of the supported architectures.
  139. X *  2.  For every accessible object, a pointer to it is stored in
  140. X *          a) the stack segment, or
  141. X *          b) the data or bss segment, or
  142. X *          c) the registers, or
  143. X *          d) an accessible block.
  144. X *
  145. X */
  146. X
  147. X/*
  148. X * Separate free lists are maintained for different sized objects
  149. X * up to MAXOBJSZ or MAXAOBJSZ.
  150. X * The lists objfreelist[i] contain free objects of size i which may
  151. X * contain nested pointers.  The lists aobjfreelist[i] contain free
  152. X * atomic objects, which may not contain nested pointers.
  153. X * The call allocobj(i) insures that objfreelist[i] points to a non-empty
  154. X * free list it returns a pointer to the first entry on the free list.
  155. X * Allocobj may be called from C to allocate an object of (small) size i
  156. X * as follows:
  157. X *
  158. X *            opp = &(objfreelist[i]);
  159. X *            if (*opp == (struct obj *)0) allocobj(i);
  160. X *            ptr = *opp;
  161. X *            *opp = ptr->next;
  162. X *
  163. X * Note that this is very fast if the free list is non-empty; it should
  164. X * only involve the execution of 4 or 5 simple instructions.
  165. X * All composite objects on freelists are cleared, except for
  166. X * their first longword.
  167. X */
  168. X
  169. X/*
  170. X *  The allocator uses allochblk to allocate large chunks of objects.
  171. X * These chunks all start on addresses which are multiples of
  172. X * HBLKSZ.  All starting addresses are maintained on a contiguous
  173. X * list so that they can be traversed in the sweep phase of garbage collection.
  174. X * This makes it possible to check quickly whether an
  175. X * arbitrary address corresponds to an object administered by the
  176. X * allocator.
  177. X *  We make the (probably false) claim that this can be interrupted
  178. X * by a signal with at most the loss of some chunk of memory.
  179. X */
  180. X
  181. X/* Declarations for fundamental data structures.  These are grouped */
  182. X/* in a single structure, so that the collector can skip over them. */
  183. X
  184. Xstruct __gc_arrays _gc_arrays;
  185. X
  186. Xlong heapsize = 0;      /* Heap size in bytes */
  187. X
  188. Xlong non_gc_bytes = 0;  /* Number of bytes not intended to be collected */
  189. X
  190. Xchar copyright[] = "Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers";
  191. X
  192. X/* Return a rough approximation to the stack pointer.  A hack,  */
  193. X/* but it's semi-portable.                                      */
  194. Xword * get_current_sp()
  195. X{
  196. X    word x;
  197. X    return(&x);
  198. X}
  199. X
  200. X/*
  201. X * Allocate a new heapblock for objects of size n.
  202. X * Add all of the heapblock's objects to the free list for objects
  203. X * of that size.  A negative n requests atomic objects.
  204. X */
  205. Xvoid new_hblk(n)
  206. Xlong n;
  207. X{
  208. X    register word *p,
  209. X          *r;
  210. X    word *last_object;        /* points to last object in new hblk    */
  211. X    register struct hblk *h;    /* the new heap block            */
  212. X    register long abs_sz;    /* |n|    */
  213. X    register int i;
  214. X
  215. X#   ifdef PRINTSTATS
  216. X    if ((sizeof (struct hblk)) > HBLKSIZE) {
  217. X        abort("HBLK SZ inconsistency");
  218. X        }
  219. X#   endif
  220. X
  221. X  /* Allocate a new heap block */
  222. X    h = allochblk(n);
  223. X
  224. X  /* Add it to hblklist */
  225. X    add_hblklist(h);
  226. X
  227. X  /* Add objects to free list */
  228. X    abs_sz = abs(n);
  229. X    p = &(h -> hb_body[abs_sz]);    /* second object in *h    */
  230. X    r = &(h -> hb_body[0]);           /* One object behind p    */
  231. X    last_object = ((word *)((char *)h + HBLKSIZE)) - abs_sz;
  232. X                /* Last place for last object to start */
  233. X
  234. X  /* make a list of all objects in *h with head as last object */
  235. X    while (p <= last_object) {
  236. X      /* current object's link points to last object */
  237. X    ((struct obj *)p) -> obj_link = (struct obj *)r;
  238. X    r = p;
  239. X    p += abs_sz;
  240. X    }
  241. X    p -= abs_sz;            /* p now points to last object */
  242. X
  243. X  /*
  244. X   * put p (which is now head of list of objects in *h) as first
  245. X   * pointer in the appropriate free list for this size.
  246. X   */
  247. X    if (n < 0) {
  248. X    ((struct obj *)(h -> hb_body)) -> obj_link = aobjfreelist[abs_sz];
  249. X    aobjfreelist[abs_sz] = ((struct obj *)p);
  250. X    } else {
  251. X    ((struct obj *)(h -> hb_body)) -> obj_link = objfreelist[abs_sz];
  252. X    objfreelist[abs_sz] = ((struct obj *)p);
  253. X    }
  254. X
  255. X  /*
  256. X   * Set up mask in header to facilitate alignment checks
  257. X   * See "runtime.h" for a description of how this works.
  258. X   */
  259. X#   ifndef RT
  260. X    switch (abs_sz) {
  261. X        case 1:
  262. X        h -> hb_mask = 0x3;
  263. X        break;
  264. X        case 2:
  265. X        h -> hb_mask = 0x7;
  266. X        break;
  267. X        case 4:
  268. X        h -> hb_mask = 0xf;
  269. X        break;
  270. X        case 8:
  271. X        h -> hb_mask = 0x1f;
  272. X        break;
  273. X        case 16:
  274. X        h -> hb_mask = 0x3f;
  275. X        break;
  276. X        /* By default it remains set to a negative value */
  277. X    }
  278. X#   else
  279. X      /* the 4.2 pcc C compiler did not produce correct code for the switch */
  280. X    if (abs_sz == 1)    { h -> hb_mask = 0x3; }
  281. X    else if (abs_sz == 2)    { h -> hb_mask = 0x7; }
  282. X    else if (abs_sz == 4)    { h -> hb_mask = 0xf; }
  283. X    else if (abs_sz == 8)    { h -> hb_mask = 0x1f; }
  284. X    else if (abs_sz == 16)    { h -> hb_mask = 0x3f; }
  285. X    /* else skip; */
  286. X#   endif
  287. X
  288. X#   ifdef DEBUG
  289. X    printf("Allocated new heap block at address 0x%X\n",
  290. X        h);
  291. X#   endif
  292. X}
  293. X
  294. X
  295. X/* some more variables */
  296. X
  297. Xextern long mem_found;  /* Number of reclaimed longwords */
  298. X            /* after garbage collection      */
  299. X
  300. Xextern long atomic_in_use, composite_in_use;
  301. Xextern errno;
  302. X
  303. X/*
  304. X * Clear mark bits in all allocated heap blocks
  305. X */
  306. Xstatic void clear_marks()
  307. X{
  308. X    register int j;
  309. X    register struct hblk **p;
  310. X    register struct hblk *q;
  311. X
  312. X# ifdef HBLK_MAP
  313. X    for (q = (struct hblk *) heapstart; ((char*)q) < heaplim; q++)
  314. X      if (is_hblk(q)) {
  315. X# else
  316. X    for (p = hblklist; p < last_hblk; p++) {
  317. X    q = *p;
  318. X# endif
  319. X        for (j = 0; j < MARK_BITS_SZ; j++) {
  320. X        q -> hb_marks[j] = 0;
  321. X        }
  322. X    }
  323. X}
  324. X
  325. X/* Limits of stack for mark routine.  Set by caller to mark.           */
  326. X/* All items between mark_stack_top and mark_stack_bottom-1 still need */
  327. X/* to be marked.  All items on the stack satisfy quicktest.  They do   */
  328. X/* not necessarily reference real objects.                             */
  329. Xword * mark_stack_bottom;
  330. Xword * mark_stack_top;
  331. X
  332. X#ifdef USE_STACK
  333. X# define STACKGAP 512 /* Gap in longwords between hardware stack and    */
  334. X              /* the mark stack.                */
  335. X#endif
  336. X
  337. X
  338. X#ifdef USE_STACK
  339. X#   define PUSH_MS(ptr) *(--mark_stack_top) = (word) ptr
  340. X#   define NOT_DONE(a,b) (a < b)
  341. X#else
  342. X# ifdef USE_HEAP
  343. X    char *cur_break = 0;
  344. X
  345. X#   define STACKINCR 0x4000
  346. X#   define PUSH_MS(ptr)                         \
  347. X    mark_stack_top++;                                               \
  348. X    if ((char*)mark_stack_top >= cur_break) {             \
  349. X        if (sbrk(STACKINCR) == -1) {                \
  350. X        fprintf(stderr, "sbrk failed, code = %d\n",errno);      \
  351. X        exit(1);                        \
  352. X        } else {                            \
  353. X        cur_break += STACKINCR;                                \
  354. X        }                                \
  355. X    }                                \
  356. X    *mark_stack_top = (word) ptr
  357. X#   define NOT_DONE(a,b) (a > b)
  358. X# else
  359. X    --> where does the mark stack go? <--
  360. X# endif
  361. X#endif
  362. X
  363. X
  364. X/* Top level mark routine */
  365. Xtl_mark(p)
  366. Xword * p;
  367. X{
  368. X    if (quicktest(p)) {
  369. X    /* Allocate mark stack, leaving a hole below the real stack. */
  370. X#         ifdef USE_STACK
  371. X        mark_stack_bottom = get_current_sp() - STACKGAP;
  372. X        mark_stack_top = mark_stack_bottom;
  373. X#         else
  374. X#           ifdef USE_HEAP
  375. X          mark_stack_bottom = (word *) sbrk(0); /* current break */
  376. X          cur_break = (char *) mark_stack_bottom;
  377. X          mark_stack_top = mark_stack_bottom;
  378. X#           else
  379. X          -> then where should the mark stack go ? <-
  380. X#           endif
  381. X#         endif
  382. X    PUSH_MS((word)p);
  383. X
  384. X#       ifdef DEBUG2
  385. X        printf("Tl_mark found plausible pointer: %X\n", p);
  386. X#       endif
  387. X
  388. X    /* and now mark the one element on the stack */
  389. X      mark();
  390. X    }
  391. X}
  392. X
  393. Xmark()
  394. X{
  395. X  register long sz;
  396. X  extern char end, etext;
  397. X  register struct obj *p; /* pointer to current object to be marked */
  398. X
  399. X  while (NOT_DONE(mark_stack_top,mark_stack_bottom)) {
  400. X      register long word_no;
  401. X      register long mask;
  402. X      register struct hblk * h;
  403. X
  404. X#    ifdef USE_STACK
  405. X      p = (struct obj *)(*mark_stack_top++);
  406. X#    else
  407. X#     ifdef USE_HEAP
  408. X    p = (struct obj *)(*mark_stack_top--);
  409. X#     else
  410. X    --> fixit <--
  411. X#     endif
  412. X#    endif
  413. X
  414. X  /* if not a pointer to obj on heap, skip it */
  415. X    if (((char *) p) >= heaplim) {
  416. X    continue;
  417. X    }
  418. X
  419. X    h = HBLKPTR(p);
  420. X
  421. X# ifndef INTERIOR_POINTERS
  422. X    /* Check mark bit first, since this test is much more likely to */
  423. X    /* fail than later ones.                                        */
  424. X      word_no = ((word *)p) - ((word *)h);
  425. X      if (mark_bit(h, word_no)) {
  426. X    continue;
  427. X      }
  428. X# endif
  429. X
  430. X# ifdef INTERIOR_POINTERS
  431. X    if (!is_hblk(h)) {
  432. X    char m = get_map(h);
  433. X    while (m > 0 && m < 0x7f) {
  434. X        h -= m;
  435. X        m = get_map(h);
  436. X    }
  437. X    if (m == HBLK_INVALID) {
  438. X#         ifdef REPORT_FAILURE
  439. X        printf("-> Pointer to non-heap loc: %X\n", p);
  440. X#         endif
  441. X      continue;
  442. X    }
  443. X    }
  444. X    if (((long)p) - ((long)h) < sizeof (struct hblkhdr)) {
  445. X    continue;
  446. X    }
  447. X# else
  448. X    if (!is_hblk(h)) {
  449. X#    ifdef REPORT_FAILURE
  450. X      printf("-> Pointer to non-heap loc: %X\n", p);
  451. X#       endif
  452. X    continue;
  453. X    }
  454. X# endif
  455. X    sz = HB_SIZE(h);
  456. X    mask = h -> hb_mask;
  457. X
  458. X# ifdef INTERIOR_POINTERS
  459. X    word_no = get_word_no(p,h,sz,mask);
  460. X# else
  461. X    if (!is_proper_obj(p,h,sz,mask)) {
  462. X#       ifdef REPORT_FAILURE
  463. X        printf("-> Bad pointer to heap block: %X,sz = %d\n",p,sz);
  464. X#    endif
  465. X    continue;
  466. X    }
  467. X# endif
  468. X
  469. X    if (word_no + sz > BYTES_TO_WORDS(HBLKSIZE)
  470. X    && word_no != BYTES_TO_WORDS(sizeof(struct hblkhdr))
  471. X       /* Not first object */) {
  472. X      /* 
  473. X       * Note that we dont necessarily check for pointers to the block header.
  474. X       * This doesn't cause any problems, since we have mark
  475. X       * bits allocated for such bogus objects.
  476. X       * We have to check for references past the last object, since
  477. X       * marking from uch an "object" could cause an exception.
  478. X       */
  479. X#       ifdef REPORT_FAILURE
  480. X        printf("-> Bad pointer to heap block: %X,sz = %d\n",p,sz);
  481. X#    endif
  482. X    continue;
  483. X    }
  484. X
  485. X#   ifdef INTERIOR_POINTERS
  486. X      if (mark_bit(h, word_no)) {
  487. X    continue;
  488. X      }
  489. X#   endif
  490. X
  491. X#   ifdef DEBUG2
  492. X    printf("*** set bit for heap %x, word %x\n",h,word_no);
  493. X#   endif
  494. X    set_mark_bit(h, word_no);
  495. X    if (h -> hb_sz < 0) {
  496. X    /* Atomic object */
  497. X      continue;
  498. X    }
  499. X    {
  500. X      /* Mark from fields inside the object */
  501. X    register struct obj ** q;
  502. X    register struct obj * r;
  503. X    register long lim;   /* Should be struct obj **, but we're out of */
  504. X                 /* A registers on a 68000.                   */
  505. X
  506. X#       ifdef INTERIOR_POINTERS
  507. X      /* Adjust p, so that it's properly aligned */
  508. X#           ifdef DEBUG
  509. X          if (p != ((struct obj *)(((word *)h) + word_no))) {
  510. X        printf("Adjusting from %X to ", p);
  511. X        p = ((struct obj *)(((word *)h) + word_no));
  512. X        printf("%X\n", p);
  513. X          } else {
  514. X        p = ((struct obj *)(((word *)h) + word_no));
  515. X          }
  516. X#           else
  517. X          p = ((struct obj *)(((word *)h) + word_no));
  518. X#           endif
  519. X#       endif
  520. X#       ifdef UNALIGNED
  521. X      lim = ((long)(&(p -> obj_component[sz]))) - 3;
  522. X#       else
  523. X      lim = (long)(&(p -> obj_component[sz]));
  524. X#       endif
  525. X    for (q = (struct obj **)(&(p -> obj_component[0]));
  526. X                    q < (struct obj **)lim;) {
  527. X        r = *q;
  528. X        if (quicktest(r)) {
  529. X#               ifdef DEBUG2
  530. X            printf("Found plausible nested pointer");
  531. X            printf(": 0x%X inside 0x%X at 0x%X\n", r, p, q);
  532. X#               endif
  533. X        PUSH_MS(((word)r));
  534. X        }
  535. X#           ifdef UNALIGNED
  536. X        q = ((struct obj **)(((long)q)+ALIGNMENT));
  537. X#           else
  538. X        q++;
  539. X#           endif 
  540. X    }
  541. X    }
  542. X  }
  543. X}
  544. X
  545. X
  546. X/*********************************************************************/
  547. X/* Mark all locations reachable via pointers located between b and t */
  548. X/*********************************************************************/
  549. Xmark_all(b, t)
  550. Xword * b;
  551. Xword * t;
  552. X{
  553. X    register word *p;
  554. X    register word r;
  555. X    register word *lim;
  556. X
  557. X#   ifdef DEBUG
  558. X    printf("Checking for pointers between 0x%X and 0x%X\n",
  559. X        b, t);
  560. X#   endif
  561. X
  562. X    /* Allocate mark stack, leaving a hole below the real stack. */
  563. X#     ifdef USE_STACK
  564. X    mark_stack_bottom = get_current_sp() - STACKGAP;
  565. X    mark_stack_top = mark_stack_bottom;
  566. X#     else
  567. X#       ifdef USE_HEAP
  568. X      mark_stack_bottom = (word *) sbrk(0); /* current break */
  569. X      cur_break = (char *) mark_stack_bottom;
  570. X      mark_stack_top = mark_stack_bottom;
  571. X#       else
  572. X      -> then where should the mark stack go ? <-
  573. X#       endif
  574. X#     endif
  575. X
  576. X  /* Round b down so it is properly aligned */
  577. X#   if (ALIGNMENT == 2)
  578. X      b = (word *)(((long) b) & ~1);
  579. X#   else
  580. X#     if (ALIGNMENT == 4 || !defined(UNALIGNED))
  581. X    b = (word *)(((long) b) & ~3);
  582. X#     endif
  583. X#   endif
  584. X
  585. X  /* check all pointers in range and put on mark_stack if quicktest true */
  586. X    lim = t - 1 /* longword */;
  587. X    for (p = b; ((unsigned) p) <= ((unsigned) lim);) {
  588. X        /* Coercion to unsigned in the preceding appears to be necessary */
  589. X        /* due to a bug in the VAX C compiler.                           */
  590. X    r = *p;
  591. X    if (quicktest(r)) {
  592. X#           ifdef DEBUG2
  593. X        printf("Found plausible pointer: %X\n", r);
  594. X#           endif
  595. X        PUSH_MS(r);         /* push r onto the mark stack */
  596. X    }
  597. X#       ifdef UNALIGNED
  598. X      p = (word *)(((char *)p) + ALIGNMENT);
  599. X#       else
  600. X      p++;
  601. X#       endif
  602. X    }
  603. X    if (mark_stack_top != mark_stack_bottom) mark();
  604. X
  605. X#   ifdef USE_HEAP
  606. X      brk(mark_stack_bottom);     /* reset break to where it was before */
  607. X      cur_break = (char *) mark_stack_bottom;
  608. X#   endif
  609. X}
  610. X
  611. X/*
  612. X * Restore inaccessible objects to the free list 
  613. X * update mem_found (number of reclaimed longwords after garbage collection)
  614. X */
  615. Xvoid gcollect()
  616. X{
  617. X    extern void mark_regs();
  618. X    register long TMP_SP; /* must be bound to r11 on VAX or RT, d7 on M68K */
  619. X              /* or r3 on NS32K                                */
  620. X
  621. X    extern int holdsigs();  /* disables non-urgent signals - see the    */
  622. X                /* file "callcc.c"                */
  623. X
  624. X    long Omask;        /* mask to restore signal mask to after
  625. X             * critical section.  This variable is assumed
  626. X             * to be the first variable on the stack frame
  627. X             * and to be longword aligned.
  628. X             */
  629. X
  630. X#   ifdef PRINTTIMES
  631. X      /* some debugging values */
  632. X    double start_time;
  633. X    double mark_time;
  634. X    double done_time;
  635. X    struct tms time_buf;
  636. X#       define FTIME \
  637. X         (((double)(time_buf.tms_utime + time_buf.tms_stime))/60.0)
  638. X
  639. X      /* Get starting time */
  640. X        times(&time_buf);
  641. X        start_time = FTIME;
  642. X#   endif
  643. X
  644. X#   ifdef DEBUG2
  645. X    printf("Here we are in gcollect\n"); 
  646. X#   endif
  647. X
  648. X    /* Don't want to deal with signals in the middle so mask 'em out */
  649. X    Omask = holdsigs();
  650. X
  651. X    /*
  652. X     * mark from registers - i.e., call tl_mark(i) for each
  653. X     * register i
  654. X     */
  655. X    mark_regs();
  656. X
  657. X#       ifdef DEBUG
  658. X        printf("done marking from regs - calling mark_all\n");
  659. X#    endif
  660. X
  661. X      /* put stack pointer into TMP_SP               */
  662. X      /* and mark everything on the stack.           */
  663. X    /* A hack */
  664. X    TMP_SP = ((long)(&Omask));
  665. X    mark_all( TMP_SP, STACKTOP );
  666. X
  667. X
  668. X    /* Mark everything in data and bss segments.                             */
  669. X    /* Skip gc data structures. (It's OK to mark these, but it wastes time.) */
  670. X    {
  671. X        extern char etext, end;
  672. X
  673. X            mark_all(DATASTART, begin_gc_arrays);
  674. X            mark_all(end_gc_arrays, &end);
  675. X    }
  676. X
  677. X    /* Clear free list mark bits, in case they got accidentally marked   */
  678. X    /* Note: HBLKPTR(p) == pointer to head of block containing *p        */
  679. X    /* Also subtract memory remaining from mem_found count.              */
  680. X    /* Note that composite objects on free list are cleared.             */
  681. X    /* Thus accidentally marking a free list is not a problem;  only     */
  682. X    /* objects on the list itself will be marked, and that's fixed here. */
  683. X      {
  684. X    register int size;        /* current object size        */
  685. X    register struct obj * p;    /* pointer to current object    */
  686. X    register struct hblk * q;    /* pointer to block containing *p */
  687. X    register int word_no;           /* "index" of *p in *q          */
  688. X#       ifdef REPORT_FAILURE
  689. X        int prev_failure = 0;
  690. X#       endif
  691. X
  692. X    for (size = 1; size < MAXOBJSZ; size++) {
  693. X        for (p= objfreelist[size]; p != ((struct obj *)0); p=p->obj_link){
  694. X        q = HBLKPTR(p);
  695. X        word_no = (((word *)p) - ((word *)q));
  696. X#               ifdef REPORT_FAILURE
  697. X          if (!prev_failure && mark_bit(q, word_no)) {
  698. X            printf("-> Pointer to composite free list: %X,sz = %d\n",
  699. X                p, size);
  700. X            prev_failure = 1;
  701. X          }
  702. X#               endif
  703. X        clear_mark_bit(q, word_no);
  704. X        mem_found -= size;
  705. X        }
  706. X#           ifdef REPORT_FAILURE
  707. X        prev_failure = 0;
  708. X#           endif
  709. X    }
  710. X    for (size = 1; size < MAXAOBJSZ; size++) {
  711. X        for(p= aobjfreelist[size]; p != ((struct obj *)0); p=p->obj_link){
  712. X        q = HBLKPTR(p);
  713. X        word_no = (((long *)p) - ((long *)q));
  714. X#               ifdef REPORT_FAILURE
  715. X          if (!prev_failure && mark_bit(q, word_no)) {
  716. X            printf("-> Pointer to atomic free list: %X,sz = %d\n",
  717. X                p, size);
  718. X            prev_failure = 1;
  719. X          }
  720. X#               endif
  721. X        clear_mark_bit(q, word_no);
  722. X        mem_found -= size;
  723. X        }
  724. X#           ifdef REPORT_FAILURE
  725. X        prev_failure = 0;
  726. X#           endif
  727. X    }
  728. X      }
  729. X
  730. X#   ifdef PRINTTIMES
  731. X      /* Get intermediate time */
  732. X    times(&time_buf);
  733. X    mark_time = FTIME;
  734. X#   endif
  735. X
  736. X#   ifdef PRINTSTATS
  737. X    printf("Bytes recovered before reclaim - f.l. count = %d\n",
  738. X           WORDS_TO_BYTES(mem_found));
  739. X#   endif
  740. X
  741. X  /* Reconstruct free lists to contain everything not marked */
  742. X    reclaim();
  743. X
  744. X  /* clear mark bits in all allocated heap blocks */
  745. X    clear_marks();
  746. X
  747. X#   ifdef PRINTSTATS
  748. X    printf("Reclaimed %d bytes in heap of size %d bytes\n",
  749. X           WORDS_TO_BYTES(mem_found), heapsize);
  750. X    printf("%d (atomic) + %d (composite) bytes in use\n",
  751. X           WORDS_TO_BYTES(atomic_in_use),
  752. X           WORDS_TO_BYTES(composite_in_use));
  753. X#   endif
  754. X
  755. X  /*
  756. X   * What follows is somewhat heuristic.  Constant may benefit
  757. X   * from tuning ...
  758. X   */
  759. X    if (WORDS_TO_BYTES(mem_found) * 4 < heapsize) {
  760. X      /* Less than about 1/4 of available memory was reclaimed - get more */
  761. X    {
  762. X        long size_to_get = HBLKSIZE + hincr * HBLKSIZE;
  763. X        struct hblk * thishbp;
  764. X        char * nheaplim;
  765. X
  766. X        thishbp = HBLKPTR(((unsigned)sbrk(0))+HBLKSIZE-1 );
  767. X        nheaplim = (char *) (((unsigned)thishbp) + size_to_get);
  768. X        if( ((char *) brk(nheaplim)) == ((char *)-1) ) {
  769. X        write(2,"Out of memory, trying to continue ...\n",38);
  770. X        } else {
  771. X        heaplim = nheaplim;
  772. X        thishbp->hb_sz = 
  773. X            BYTES_TO_WORDS(size_to_get - sizeof(struct hblkhdr));
  774. X        freehblk(thishbp);
  775. X        heapsize += size_to_get;
  776. X        update_hincr;
  777. X        }
  778. X#           ifdef PRINTSTATS
  779. X        printf("Gcollect: needed to increase heap size by %d\n",
  780. X               size_to_get);
  781. X#           endif
  782. X    }
  783. X    }
  784. X
  785. X   /* Reset mem_found for next collection */
  786. X     mem_found = 0;
  787. X
  788. X  /* Reenable signals */
  789. X    sigsetmask(Omask);
  790. X
  791. X  /* Get final time */
  792. X#   ifdef PRINTTIMES
  793. X    times(&time_buf);
  794. X    done_time = FTIME;
  795. X    printf("Garbage collection took %7.2f + %7.2f secs\n",
  796. X           mark_time - start_time, done_time - mark_time);
  797. X#   endif
  798. X}
  799. X
  800. X/*
  801. X * this is a function callable from Russell to explicity make the heap
  802. X * bigger for use by programs which know they'll need a bigger heap than
  803. X * the default.
  804. X */
  805. Xvoid expand_hp(n)
  806. Xint n;
  807. X{
  808. X    struct hblk * thishbp = HBLKPTR(((unsigned)sbrk(0))+HBLKSIZE-1 );
  809. X    extern int holdsigs();
  810. X    int Omask;
  811. X
  812. X    /* Don't want to deal with signals in the middle of this */
  813. X    Omask = holdsigs();
  814. X
  815. X    heaplim = (char *) (((unsigned)thishbp) + n * HBLKSIZE);
  816. X    if (n > 2*hincr) {
  817. X    hincr = n/2;
  818. X    }
  819. X    if( ((char *) brk(heaplim)) == ((char *)-1) ) {
  820. X    write(2,"Out of Memory!\n",15);
  821. X    exit(-1);
  822. X    }
  823. X#   ifdef PRINTSTATS
  824. X    printf("Voluntarily increasing heap size by %d\n",
  825. X           n*HBLKSIZE);
  826. X#   endif
  827. X    thishbp->hb_sz = BYTES_TO_WORDS(n * HBLKSIZE - sizeof(struct hblkhdr));
  828. X    freehblk(thishbp);
  829. X    heapsize += ((char *)heaplim) - ((char *)thishbp);
  830. X    /* Reenable signals */
  831. X    sigsetmask(Omask);
  832. X}
  833. X
  834. X
  835. Xextern int dont_gc;  /* Unsafe to start garbage collection */
  836. X
  837. X/*
  838. X * Make sure the composite object free list for sz is not empty.
  839. X * Return a pointer to the first object on the free list.
  840. X * The object MUST BE REMOVED FROM THE FREE LIST BY THE CALLER.
  841. X *
  842. X * note: _allocobj
  843. X */
  844. Xstruct obj * _allocobj(sz)
  845. Xlong sz;
  846. X{
  847. X    if (sz == 0) return((struct obj *)0);
  848. X
  849. X#   ifdef DEBUG2
  850. X    printf("here we are in _allocobj\n");
  851. X#   endif
  852. X
  853. X    if (objfreelist[sz] == ((struct obj *)0)) {
  854. X      if (hblkfreelist == ((struct hblk *)0) && !dont_gc) {
  855. X    if (GC_DIV * non_gc_bytes < GC_MULT * heapsize) {
  856. X#         ifdef DEBUG
  857. X        printf("Calling gcollect\n");
  858. X#         endif
  859. X      gcollect();
  860. X    } else {
  861. X      expand_hp(NON_GC_HINCR);
  862. X    }
  863. X      }
  864. X      if (objfreelist[sz] == ((struct obj *)0)) {
  865. X#       ifdef DEBUG
  866. X        printf("Calling new_hblk\n");
  867. X#    endif
  868. X      new_hblk(sz);
  869. X      }
  870. X    }
  871. X#   ifdef DEBUG2
  872. X    printf("Returning %x from _allocobj\n",objfreelist[sz]);
  873. X    printf("Objfreelist[%d] = %x\n",sz,objfreelist[sz]);
  874. X#   endif
  875. X    return(objfreelist[sz]);
  876. X}
  877. X
  878. X/*
  879. X * Make sure the atomic object free list for sz is not empty.
  880. X * Return a pointer to the first object on the free list.
  881. X * The object MUST BE REMOVED FROM THE FREE LIST BY THE CALLER.
  882. X *
  883. X * note: this is called by allocaobj (see the file allocobj.s)
  884. X */
  885. Xstruct obj * _allocaobj(sz)
  886. Xlong sz;
  887. X{
  888. X    if (sz == 0) return((struct obj *)0);
  889. X
  890. X    if (aobjfreelist[sz] == ((struct obj *) 0)) {
  891. X      if (hblkfreelist == ((struct hblk *)0) && !dont_gc) {
  892. X    if (GC_DIV * non_gc_bytes < GC_MULT * heapsize) {
  893. X#         ifdef DEBUG
  894. X        printf("Calling gcollect\n");
  895. X#         endif
  896. X      gcollect();
  897. X    } else {
  898. X      expand_hp(NON_GC_HINCR);
  899. X    }
  900. X      }
  901. X      if (aobjfreelist[sz] == ((struct obj *) 0)) {
  902. X      new_hblk(-sz);
  903. X      }
  904. X    }
  905. X    return(aobjfreelist[sz]);
  906. X}
  907. X
  908. X# ifdef SPARC
  909. X  put_mark_stack_bottom(val)
  910. X  long val;
  911. X  {
  912. X    mark_stack_bottom = (word *)val;
  913. X  }
  914. X# endif
  915. /
  916. echo 'Extracting misc.c...'
  917. sed 's/^X//' > misc.c << '/'
  918. X#define DEBUG       /* Some run-time consistency checks */
  919. X#undef DEBUG
  920. X#define VERBOSE
  921. X#undef VERBOSE
  922. X
  923. X#include <stdio.h>
  924. X#include <signal.h>
  925. X#include "runtime.h"
  926. X
  927. Xint dont_gc = 0;
  928. Xextern long mem_found;
  929. X
  930. X# ifdef MERGE_SIZES
  931. X#   if MAXOBJSZ == MAXAOBJSZ
  932. X#       define MAXSZ MAXOBJSZ
  933. X#   else
  934. X    --> causes problems here, since we cant map any size to a
  935. X        size that doesn't have a free list.  Either initialization
  936. X        needs to be cleverer, or we need separate maps for atomic
  937. X        and composite objects.
  938. X#   endif
  939. X    long size_map[MAXSZ+1];
  940. X
  941. X    /* Set things up so that size_map[i] >= i, but not too much bigger */
  942. X    /* and so that size_map contains relatively few distinct entries   */
  943. X    void init_size_map()
  944. X    {
  945. X    register int i;
  946. X    register int i_rounded_up = 0;
  947. X
  948. X    for (i = 1; i < 8; i++) {
  949. X        size_map[i] = i;
  950. X    }
  951. X    for (i = 8; i <= MAXSZ; i++) {
  952. X        if (i_rounded_up < i) {
  953. X        i_rounded_up = i + (i >> 1);
  954. X        if (i_rounded_up > MAXSZ) {
  955. X            i_rounded_up = MAXSZ;
  956. X        }
  957. X        }
  958. X        size_map[i] = i_rounded_up;
  959. X    }
  960. X    }
  961. X# endif
  962. X
  963. X
  964. X/* allocate lb bytes of atomic data */
  965. Xstruct obj * gc_malloc_atomic(lb)
  966. Xint lb;
  967. X{
  968. Xregister struct obj *op;
  969. Xregister struct obj **opp;
  970. Xregister int lw = BYTES_TO_WORDS(lb + (sizeof (word)) -1);
  971. X
  972. X#   ifdef VERBOSE
  973. X    printf("Here we are in gc_malloc_atomic(%d)\n",lw);
  974. X#   endif
  975. X    if( lw <= MAXAOBJSZ ) {
  976. X#       ifdef MERGE_SIZES
  977. X      lw = size_map[lw];
  978. X#       endif
  979. X    opp = &(aobjfreelist[lw]);
  980. X        if( (op = *opp) == ((struct obj *)0) ) {
  981. X            op = allocaobj(lw);
  982. X        }
  983. X#       ifdef DEBUG
  984. X        if ((op -> obj_link != ((struct obj *) 0)
  985. X        && (((unsigned)(op -> obj_link)) > ((unsigned) HEAPLIM)
  986. X           || ((unsigned)(op -> obj_link)) < ((unsigned) HEAPSTART)))) {
  987. X        fprintf(stderr, "Bad free list in gc_malloc_atomic\n");
  988. X        abort(op);
  989. X            }
  990. X#       endif
  991. X        *opp = op->obj_link;
  992. X        op->obj_link = (struct obj *)0;
  993. X    } else {
  994. X    register struct hblk * h;
  995. X    if (!sufficient_hb(-lw) && !dont_gc) {
  996. X            gcollect();
  997. X    }
  998. X#       ifdef VERBOSE
  999. X        printf("gc_malloc_atomic calling allochblk(%x)\n",lw);
  1000. X#    endif
  1001. X    h = allochblk(-lw);
  1002. X    add_hblklist(h);
  1003. X    op = (struct obj *) (h -> hb_body);
  1004. X    }
  1005. X    return(op);
  1006. X}
  1007. X
  1008. X/* allocate lw bytes of possibly composite data */
  1009. Xstruct obj * gc_malloc(lb)
  1010. Xint lb;
  1011. X{
  1012. Xregister struct obj *op;
  1013. Xregister struct obj **opp;
  1014. Xregister int lw = BYTES_TO_WORDS(lb + (sizeof (word)) -1);
  1015. X
  1016. X    if( lw <= MAXOBJSZ ) {
  1017. X#       ifdef MERGE_SIZES
  1018. X      lw = size_map[lw];
  1019. X#       endif
  1020. X    opp = &(objfreelist[lw]);
  1021. X        if( (op = *opp) == ((struct obj *)0) ) {
  1022. X        op = allocobj(lw);
  1023. X        }
  1024. X#       ifdef DEBUG
  1025. X        if ((op -> obj_link != ((struct obj *) 0)
  1026. X        && (((unsigned)(op -> obj_link)) > ((unsigned) HEAPLIM)
  1027. X           || ((unsigned)(op -> obj_link)) < ((unsigned) HEAPSTART)))) {
  1028. X        fprintf(stderr, "Bad free list in gc_malloc\n");
  1029. X        abort(op);
  1030. X            }
  1031. X#       endif
  1032. X        *opp = op->obj_link;
  1033. X        op->obj_link = (struct obj *)0;
  1034. X    } else {
  1035. X    register struct hblk * h;
  1036. X
  1037. X    if (!sufficient_hb(lw) && !dont_gc) {
  1038. X            gcollect();
  1039. X    }
  1040. X#       ifdef VERBOSE
  1041. X        printf("ralloc_comp calling allochblk(%x)\n",lw);
  1042. X#    endif
  1043. X    h = allochblk(lw);
  1044. X    add_hblklist(h);
  1045. X    op = (struct obj *) (h -> hb_body);
  1046. X    }
  1047. X    return(op);
  1048. X}
  1049. X
  1050. X/* Explicitly deallocate an object p */
  1051. Xgc_free(p)
  1052. Xstruct obj *p;
  1053. X{
  1054. X    register struct hblk *h;
  1055. X    register int sz;
  1056. X    register word * i;
  1057. X    register word * limit;
  1058. X
  1059. X    h = HBLKPTR(p);
  1060. X    sz = h -> hb_sz;
  1061. X    if (sz < 0) {
  1062. X        sz = -sz;
  1063. X        if (sz > MAXAOBJSZ) {
  1064. X        h -> hb_uninit = 1;
  1065. X        del_hblklist(h);
  1066. X        freehblk(h);
  1067. X    } else {
  1068. X        p -> obj_link = aobjfreelist[sz];
  1069. X        aobjfreelist[sz] = p;
  1070. X    }
  1071. X    } else {
  1072. X    /* Clear the object, other than link field */
  1073. X        limit = &(p -> obj_component[sz]);
  1074. X        for (i = &(p -> obj_component[1]); i < limit; i++) {
  1075. X        *i = 0;
  1076. X        }
  1077. X    if (sz > MAXOBJSZ) {
  1078. X        p -> obj_link = 0;
  1079. X        h -> hb_uninit = 0;
  1080. X        del_hblklist(h);
  1081. X        freehblk(h);
  1082. X    } else {
  1083. X        p -> obj_link = objfreelist[sz];
  1084. X        objfreelist[sz] = p;
  1085. X    }
  1086. X    }
  1087. X    /* Add it to mem_found to prevent anomalous heap expansion */
  1088. X    /* in the event of repeated explicit frees of objects of   */
  1089. X    /* varying sizes.                                          */
  1090. X        mem_found += sz;
  1091. X}
  1092. X
  1093. X
  1094. X/*
  1095. X * Disable non-urgent signals
  1096. X */
  1097. Xint holdsigs()
  1098. X{
  1099. X    unsigned mask = 0xffffffff;
  1100. X
  1101. X    mask &= ~(1<<(SIGSEGV-1));
  1102. X    mask &= ~(1<<(SIGILL-1));
  1103. X    mask &= ~(1<<(SIGBUS-1));
  1104. X    mask &= ~(1<<(SIGIOT-1));
  1105. X    mask &= ~(1<<(SIGEMT-1));
  1106. X    mask &= ~(1<<(SIGTRAP-1));
  1107. X    mask &= ~(1<<(SIGQUIT-1));
  1108. X    return(sigsetmask(mask));
  1109. X}
  1110. X
  1111. Xvoid gc_init()
  1112. X{
  1113. X    heaplim = (char *) (sbrk(0));
  1114. X#   ifdef HBLK_MAP
  1115. X    heapstart = (char *) (HBLKPTR(((unsigned)sbrk(0))+HBLKSIZE-1 ));
  1116. X#   endif
  1117. X    hincr = HINCR;
  1118. X    expand_hp(hincr);
  1119. X    init_hblklist();
  1120. X#   ifdef MERGE_SIZES
  1121. X      init_size_map();
  1122. X#   endif
  1123. X}
  1124. X
  1125. X# ifdef MIPS
  1126. X    /* There doesn't appear a reasonable way to do this under SysV.3 */
  1127. X    sigsetmask() { return(0); }
  1128. X# endif
  1129. X
  1130. /
  1131. echo 'Extracting runtime.h...'
  1132. sed 's/^X//' > runtime.h << '/'
  1133. X/* Copyright 1988,1989 Hans-J. Boehm, Alan J. Demers */
  1134. X
  1135. X/*********************************/
  1136. X/*                               */
  1137. X/* Definitions for conservative  */
  1138. X/* collector                     */
  1139. X/*                               */
  1140. X/*********************************/
  1141. X
  1142. X/*********************************/
  1143. X/*                               */
  1144. X/* Easily changeable parameters  */
  1145. X/*                               */
  1146. X/*********************************/
  1147. X
  1148. X# if defined(sun) && defined(mc68000)
  1149. X#    define M68K
  1150. X#    define mach_type_known
  1151. X# endif
  1152. X# if defined(vax)
  1153. X#    define VAX
  1154. X#    define mach_type_known
  1155. X# endif
  1156. X# if defined(mips)
  1157. X#    define MIPS
  1158. X#    define mach_type_known
  1159. X# endif
  1160. X# if defined(sequent) && defined(i386)
  1161. X#    define I386
  1162. X#    define mach_type_known
  1163. X# endif
  1164. X# if defined(ibm032)
  1165. X#   define RT
  1166. X#   define mach_type_known
  1167. X# endif
  1168. X# if defined(sun) && defined(sparc)
  1169. X#   define SPARC
  1170. X#   define mach_type_known
  1171. X# endif
  1172. X
  1173. X
  1174. X/* Feel free to add more clauses here */
  1175. X
  1176. X/* Or manually define the machine type here: */
  1177. X# ifndef mach_type_known
  1178. X#   define M68K     /* This is a Motorola 68000, as opposed to a SPARC, VAX, */
  1179. X            /* RT, I386, MIPS, or NS32K.                             */
  1180. X            /* We assume:  M68K ==> Sun3, I386 ==> Sequent Symmetry */
  1181. X            /* NS32K ==> Encore Multimax, MIPS ==> R2000 or R3000   */
  1182. X# endif
  1183. X
  1184. X#define PRINTSTATS  /* Print garbage collection statistics                  */
  1185. X            /* For less verbose output, undefine in reclaim.c      */
  1186. X
  1187. X
  1188. X#define PRINTTIMES  /* Print the amount of time consumed by each garbage   */
  1189. X            /* collection.                                         */
  1190. X
  1191. X
  1192. X#define PRINTBLOCKS /* Print object sizes associated with heap blocks,     */
  1193. X            /* whether the objects are atomic or composite, and    */
  1194. X            /* whether or not the block was found to be empty      */
  1195. X            /* duing the reclaim phase.  Typically generates       */
  1196. X            /* about one screenful per garbage collection.         */
  1197. X#undef PRINTBLOCKS
  1198. X
  1199. X#define HBLK_MAP    /* Maintain a map of all potential heap blocks        */
  1200. X            /* starting at heapstart.                             */
  1201. X            /* Normally, this performs about as well as the       */
  1202. X            /* standard stack of chunk pointers that is used      */
  1203. X            /* otherwise.  It loses if a small section of the     */
  1204. X            /* heap consists of garbage collected objects.        */
  1205. X            /* It is ESSENTIAL if pointers to object interiors    */
  1206. X            /* are considered valid, i.e. if INTERIOR_POINTERS    */
  1207. X            /* is defined.                                        */
  1208. X#undef HBLK_MAP
  1209. X
  1210. X#define MAP_SIZE 8192  /* total data size < MAP_SIZE * HBLKSIZE = 32 Meg  */
  1211. X#define MAXHBLKS 4096  /* Maximum number of chunks which can be           */
  1212. X               /* allocated                                       */
  1213. X#define INTERIOR_POINTERS
  1214. X            /* Follow pointers to the interior of an object.      */
  1215. X            /* Substantially increases the probability of         */
  1216. X            /* unnnecessary space retention.  May be necessary    */
  1217. X            /* with gcc -O or other C compilers that may clobber  */
  1218. X            /* values of dead variables prematurely.  Pcc         */
  1219. X            /* derived compilers appear to pose no such problems. */
  1220. X            /* Empirical evidence suggests that this is probably  */
  1221. X            /* still OK for most purposes, so long as pointers    */
  1222. X            /* are known to be 32 bit aligned.  The combination   */
  1223. X            /* of INTERIOR_POINTERS and UNALIGNED (e.g. on a      */
  1224. X            /* Sun 3 with the standard compiler) causes easily    */
  1225. X            /* observable spurious retention and performance      */
  1226. X            /* degradation.                                       */
  1227. X#undef INTERIOR_POINTERS
  1228. X
  1229. X#if defined(INTERIOR_POINTERS) && !defined(HBLK_MAP)
  1230. X    --> check for interior pointers requires a heap block map
  1231. X#endif
  1232. X
  1233. X#define MERGE_SIZES /* Round up some object sizes, so that fewer distinct */
  1234. X            /* free lists are actually maintained.  This applies  */
  1235. X            /* only to the top level routines in misc.c, not to   */
  1236. X            /* user generated code that calls allocobj and        */
  1237. X            /* allocaobj directly.                                */
  1238. X            /* Slows down average programs slightly.  May however */
  1239. X            /* substantially reduce fragmentation if allocation   */
  1240. X            /* request sizes are widely scattered.                */
  1241. X#undef MERGE_SIZES
  1242. X
  1243. X
  1244. X#ifdef M68K
  1245. X#  define UNALIGNED       /* Pointers are not longword aligned         */
  1246. X#  define ALIGNMENT   2   /* Pointers are aligned on 2 byte boundaries */
  1247. X              /* by the Sun C compiler.                    */
  1248. X#else
  1249. X#  ifdef VAX
  1250. X#    undef UNALIGNED      /* Pointers are longword aligned by 4.2 C compiler */
  1251. X#    define ALIGNMENT 4
  1252. X#  else
  1253. X#    ifdef RT
  1254. X#      undef UNALIGNED
  1255. X#      define ALIGNMENT 4
  1256. X#    else
  1257. X#      ifdef SPARC
  1258. X#        undef UNALIGNED
  1259. X#        define ALIGNMENT 4
  1260. X#      else
  1261. X#        ifdef I386
  1262. X#           undef UNALIGNED         /* Sequent compiler aligns pointers */
  1263. X#           define ALIGNMENT 4
  1264. X#        else
  1265. X#          ifdef NS32K
  1266. X#            undef UNALIGNED        /* Pointers are aligned on NS32K */
  1267. X#            define ALIGNMENT 4
  1268. X#          else
  1269. X#            ifdef MIPS
  1270. X#              undef UNALIGNED      /* MIPS hardware requires pointer */
  1271. X                    /* alignment                      */
  1272. X#              define ALIGNMENT 4
  1273. X#            else
  1274. X         --> specify alignment <--
  1275. X#            endif
  1276. X#          endif
  1277. X#        endif
  1278. X#      endif
  1279. X#    endif
  1280. X#  endif
  1281. X# endif
  1282. X
  1283. X# ifdef M68K
  1284. X#   define STACKTOP ((char *)0xf000000) /* Beginning of stack on a Sun 3 */
  1285. X                    /* Sun 2 value is 0x1000000      */
  1286. X# else
  1287. X#   ifdef VAX
  1288. X#     define STACKTOP ((char *)0x80000000) /* Beginning of stack under 4.n BSD */
  1289. X#   else
  1290. X#     ifdef RT
  1291. X#       define STACKTOP ((char *) 0x1fffd800)
  1292. X#     else
  1293. X#       ifdef SPARC
  1294. X#         define STACKTOP ((char *) 0xf8000000)
  1295. X#       else
  1296. X#         ifdef I386
  1297. X#           define STACKTOP ((char *) 0x3ffff000)  /* For Sequent */
  1298. X#         else
  1299. X#           ifdef NS32K
  1300. X#             define STACKTOP ((char *) 0xfffff000) /* for Encore */
  1301. X#           else
  1302. X#             ifdef MIPS
  1303. X#               define STACKTOP ((char *) 0x7ffff000)
  1304. X                  /* Could probably be slightly lower since  */
  1305. X                  /* startup code allocates lots of junk     */
  1306. X#             else
  1307. X        --> specify
  1308. X#             endif
  1309. X#           endif
  1310. X#         endif
  1311. X#       endif
  1312. X#     endif
  1313. X#   endif
  1314. X# endif
  1315. X
  1316. X/* Start of data segment for each of the above systems.  Note that the */
  1317. X/* default case works only for contiguous text and data, such as on a  */
  1318. X/* Vax.                                                                */
  1319. X# ifdef M68K
  1320. X#   define DATASTART ((char *)((((long) (&etext)) + 0x1ffff) & ~0x1ffff))
  1321. X# else
  1322. X#   ifdef RT
  1323. X#     define DATASTART ((char *) 0x10000000)
  1324. X#   else
  1325. X#     ifdef I386
  1326. X#       define DATASTART ((char *)((((long) (&etext)) + 0xfff) & ~0xfff))
  1327. X#     else
  1328. X#       ifdef NS32K
  1329. X      extern char **environ;
  1330. X#         define DATASTART ((char *)(&environ))
  1331. X                  /* hideous kludge: environ is the first   */
  1332. X                  /* word in crt0.o, and delimits the start */
  1333. X                  /* of the data segment, no matter which   */
  1334. X                  /* ld options were passed through.        */
  1335. X#       else
  1336. X#         ifdef MIPS
  1337. X#           define DATASTART 0x10000000
  1338. X                  /* Could probably be slightly higher since */
  1339. X                  /* startup code allocates lots of junk     */
  1340. X#         else
  1341. X#           define DATASTART (&etext)
  1342. X#         endif
  1343. X#       endif
  1344. X#     endif
  1345. X#   endif
  1346. X# endif
  1347. X
  1348. X# define HINCR 16          /* Initial heap increment, in blocks of 4K        */
  1349. X# define HINCR_MULT 3      /* After each new allocation, hincr is multiplied */
  1350. X# define HINCR_DIV 2       /* by HINCR_MULT/HINCR_DIV                        */
  1351. X# define GC_MULT 3         /* Don't collect if the fraction of   */
  1352. X               /* non-collectable memory in the heap */
  1353. X               /* exceeds GC_MUL/GC_DIV              */
  1354. X# define GC_DIV  4
  1355. X
  1356. X# define NON_GC_HINCR 8    /* Heap increment if most of heap if collection */
  1357. X               /* was suppressed because most of heap is not   */
  1358. X               /* collectable                                  */
  1359. X
  1360. X/*  heap address bounds.  These are extreme bounds used for sanity checks. */
  1361. X/*  HEAPLIM may have to be increased for machines with incredibly large    */
  1362. X/*  amounts of memory.                                                     */
  1363. X
  1364. X#ifdef RT
  1365. X#   define HEAPSTART 0x10000000
  1366. X#   define HEAPLIM   0x1fff0000
  1367. X#else
  1368. X# ifdef M68K
  1369. X#   define HEAPSTART 0x00010000
  1370. X#   define HEAPLIM   0x04000000
  1371. X# else
  1372. X#   ifdef SPARC
  1373. X#       define HEAPSTART 0x00010000
  1374. X#       define HEAPLIM   0x10000000
  1375. X#   else
  1376. X#     ifdef VAX
  1377. X#       define HEAPSTART 0x400
  1378. X#       define HEAPLIM   0x10000000
  1379. X#     else
  1380. X#       ifdef I386
  1381. X#         define HEAPSTART 0x1000
  1382. X#         define HEAPLIM 0x10000000
  1383. X#       else
  1384. X#         ifdef NS32K
  1385. X#           define HEAPSTART 0x2000
  1386. X#           define HEAPLIM   0x10000000
  1387. X#         else
  1388. X#           ifdef MIPS
  1389. X#             define HEAPSTART 0x10000000
  1390. X#             define HEAPLIM 0x20000000
  1391. X#           else
  1392. X           --> values unknown <--
  1393. X#           endif
  1394. X#         endif
  1395. X#       endif
  1396. X#     endif
  1397. X#   endif
  1398. X# endif
  1399. X#endif
  1400. X
  1401. X/*********************************/
  1402. X/*                               */
  1403. X/* Machine-dependent defines     */
  1404. X/*                               */
  1405. X/*********************************/
  1406. X
  1407. X#define WORDS_TO_BYTES(x)   ((x)<<2)
  1408. X#define BYTES_TO_WORDS(x)   ((x)>>2)
  1409. X
  1410. X#define WORDSZ              32
  1411. X#define LOGWL               5    /* log[2] of above */
  1412. X#define BYTES_PER_WORD      (sizeof (word))
  1413. X#define NREGS               16
  1414. X#define ONES                0xffffffff
  1415. X#define MSBYTE              0xff000000
  1416. X#define SIGNB               0x80000000
  1417. X#define MAXSHORT            0x7fff
  1418. X#define modHALFWORDSZ(n) ((n) & 0xf)    /* mod n by size of half word    */
  1419. X#define divHALFWORDSZ(n) ((n) >> 4)    /* divide n by size of half word */
  1420. X#define modWORDSZ(n) ((n) & 0x1f)       /* mod n by size of word         */
  1421. X#define divWORDSZ(n) ((n) >> 5)         /* divide n by size of word      */
  1422. X#define twice(n) ((n) << 1)             /* double n                      */
  1423. X
  1424. Xtypedef unsigned long word;
  1425. X
  1426. X#define TRUE  1
  1427. X#define FALSE 0
  1428. X
  1429. X/*********************/
  1430. X/*                   */
  1431. X/*  Size Parameters  */
  1432. X/*                   */
  1433. X/*********************/
  1434. X
  1435. X/*  heap block size, bytes */
  1436. X/* for RT see comment below */
  1437. X
  1438. X#define HBLKSIZE   0x1000
  1439. X
  1440. X
  1441. X/*  max size objects supported by freelist (larger objects may be   */
  1442. X/*  allocated, but less efficiently)                                */
  1443. X/*      asm(".set MAXOBJSZ,0x200")      if HBLKSIZE/2 == 0x200          */
  1444. X
  1445. X#define MAXOBJSZ    (HBLKSIZE/8)
  1446. X        /* Should be BYTES_TO_WORDS(HBLKSIZE/2), but a cpp */
  1447. X        /* misfeature prevents that.                       */
  1448. X#define MAXAOBJSZ   (HBLKSIZE/8)
  1449. X
  1450. X# define divHBLKSZ(n) ((n) >> 12)
  1451. X# define modHBLKSZ(n) ((n) & 0xfff)
  1452. X# define HBLKPTR(objptr) ((struct hblk *)(((long) (objptr)) & ~0xfff))
  1453. X
  1454. X
  1455. X
  1456. X/********************************************/
  1457. X/*                                          */
  1458. X/*    H e a p   B l o c k s                 */
  1459. X/*                                          */
  1460. X/********************************************/
  1461. X
  1462. X/*  heap block header */
  1463. X#define HBLKMASK   (HBLKSIZE-1)
  1464. X
  1465. X#define BITS_PER_HBLK (HBLKSIZE * 8)
  1466. X
  1467. X#define MARK_BITS_PER_HBLK (BITS_PER_HBLK/WORDSZ)
  1468. X       /* upper bound                                    */
  1469. X       /* We allocate 1 bit/word.  Only the first word   */
  1470. X       /* in each object is actually marked.             */
  1471. X
  1472. X# define MARK_BITS_SZ ((MARK_BITS_PER_HBLK + WORDSZ - 1)/WORDSZ)
  1473. X       /* Upper bound on number of mark words per heap block  */
  1474. X
  1475. Xstruct hblkhdr {
  1476. X    long hbh_sz;    /* sz > 0 ==> objects are sz-tuples of poss. pointers */
  1477. X            /* sz < 0 ==> objects are sz-tuples not pointers      */
  1478. X            /* if free, the size in bytes of the whole block      */
  1479. X            /* Misc.c knows that hbh_sz comes first.              */
  1480. X# ifndef HBLK_MAP
  1481. X    struct hblk ** hbh_index;   /* Pointer to heap block list entry   */
  1482. X                /* for this block                     */
  1483. X# endif
  1484. X    struct hblk * hbh_next; /* Link field for hblk free list */
  1485. X    long hbh_mask;      /* If hbh_mask >= 0 then:                          */
  1486. X            /*   x % (4 * hbh_sz) == x & hbh_mask              */
  1487. X            /*   sz is a power of 2 and < the size of a heap   */
  1488. X            /*     block.                                      */
  1489. X            /* A hack to speed up pointer validity check on    */
  1490. X            /* machines with slow division.                    */
  1491. X    long hbh_marks[MARK_BITS_SZ];
  1492. X                /* Bits 2i and 2i+1 in the array refer to the   */
  1493. X                /* object starting at the ith word (header      */
  1494. X                /* INCLUDED) in the heap block.                 */
  1495. X                /* For free blocks, hbh_marks[0] = 1, indicates */
  1496. X                /* block is uninitialized.                      */
  1497. X};
  1498. X
  1499. X/*  heap block body */
  1500. X
  1501. X# define BODY_SZ ((HBLKSIZE-sizeof(struct hblkhdr))/sizeof(word))
  1502. X
  1503. Xstruct hblk {
  1504. X    struct hblkhdr hb_hdr;
  1505. X    word hb_body[BODY_SZ];
  1506. X};
  1507. X
  1508. X# define hb_sz hb_hdr.hbh_sz
  1509. X# ifndef HBLK_MAP
  1510. X#   define hb_index hb_hdr.hbh_index
  1511. X# endif
  1512. X# define hb_marks hb_hdr.hbh_marks
  1513. X# define hb_next hb_hdr.hbh_next
  1514. X# define hb_uninit hb_hdr.hbh_marks[0]
  1515. X# define hb_mask hb_hdr.hbh_mask
  1516. X
  1517. X/*  lists of all heap blocks and free lists  */
  1518. X/* Object declaration is in alloc.c          */
  1519. X/* These are grouped together in a struct    */
  1520. X/* so that they can be easily skipped by the */
  1521. X/* mark routine.                             */
  1522. X/* misc.c knows about their relative order.  */
  1523. X
  1524. Xstruct __gc_arrays {
  1525. X  struct obj * _aobjfreelist[MAXAOBJSZ+1];         /* free list for atomic objs*/
  1526. X  struct obj * _objfreelist[MAXOBJSZ+1];           /* free list for objects */
  1527. X# ifdef HBLK_MAP
  1528. X    char _hblkmap[MAP_SIZE];
  1529. X#   define HBLK_INVALID 0    /* Not administered by collector   */
  1530. X#   define HBLK_VALID 0x7f   /* Beginning of a valid heap block */
  1531. X    /* A value n, 0 < n < 0x7f denotes the continuation of a valid heap    */
  1532. X    /* block which starts at the current address - n * HBLKSIZE or earlier */
  1533. X# else
  1534. X    struct hblk * _hblklist[MAXHBLKS];
  1535. X# endif
  1536. X};
  1537. X
  1538. Xextern struct __gc_arrays _gc_arrays; 
  1539. X
  1540. X# define objfreelist _gc_arrays._objfreelist
  1541. X# define aobjfreelist _gc_arrays._aobjfreelist
  1542. X# ifdef HBLK_MAP
  1543. X#   define hblkmap _gc_arrays._hblkmap
  1544. X# else
  1545. X#   define hblklist _gc_arrays._hblklist
  1546. X# endif
  1547. X
  1548. X# define begin_gc_arrays ((char *)(&_gc_arrays))
  1549. X# define end_gc_arrays (((char *)(&_gc_arrays)) + (sizeof _gc_arrays))
  1550. X
  1551. Xstruct hblk ** last_hblk;  /* Pointer to one past the real end of hblklist */
  1552. X
  1553. Xstruct hblk * hblkfreelist;
  1554. X
  1555. Xextern long heapsize;       /* Heap size in bytes */
  1556. X
  1557. X# define HINCR 16          /* Initial heap increment, in blocks              */
  1558. Xlong hincr;                /* current heap increment, in blocks              */
  1559. X
  1560. X/* Operations */
  1561. X# define update_hincr  hincr = (hincr * HINCR_MULT)/HINCR_DIV
  1562. X# define HB_SIZE(p) abs((p) -> hb_sz)
  1563. X# define abs(x)  ((x) < 0? (-(x)) : (x))
  1564. X
  1565. X/*  procedures */
  1566. X
  1567. Xextern void
  1568. Xfreehblk();
  1569. X
  1570. Xextern struct hblk *
  1571. Xallochblk();
  1572. X
  1573. X/****************************/
  1574. X/*                          */
  1575. X/*   Objects                */
  1576. X/*                          */
  1577. X/****************************/
  1578. X
  1579. X/*  object structure */
  1580. X
  1581. Xstruct obj {
  1582. X    union {
  1583. X    struct obj *oun_link;   /* --> next object in freelist */
  1584. X#         define obj_link       obj_un.oun_link
  1585. X    word oun_component[1];  /* treats obj as list of words */
  1586. X#         define obj_component  obj_un.oun_component
  1587. X    } obj_un;
  1588. X};
  1589. X
  1590. X/*  Test whether something points to a legitimate heap object */
  1591. X
  1592. X
  1593. Xextern char end;
  1594. X
  1595. X# ifdef HBLK_MAP
  1596. X  char * heapstart; /* A lower bound on all heap addresses */
  1597. X            /* Known to be HBLKSIZE aligned.       */
  1598. X# endif
  1599. X
  1600. Xchar * heaplim;   /* 1 + last address in heap */
  1601. X
  1602. Xchar * startup_sfp; /* Frame pointer for Russell startup routine */
  1603. X
  1604. X/* Check whether the given HBLKSIZE aligned hblk pointer refers to the   */
  1605. X/* beginning of a legitimate chunk.                                      */
  1606. X/* Assumes that *p is addressable                                        */
  1607. X# ifdef HBLK_MAP
  1608. X#   define is_hblk(p)  (hblkmap[divHBLKSZ(((long)p) - ((long)heapstart))] \
  1609. X            == HBLK_VALID)
  1610. X# else
  1611. X#   define is_hblk(p) ( (p) -> hb_index >= hblklist \
  1612. X            && (p) -> hb_index < last_hblk \
  1613. X            && *((p)->hb_index) == (p))
  1614. X# endif
  1615. X# ifdef INTERIOR_POINTERS
  1616. X    /* Return the hblk_map entry for the pointer p */
  1617. X#     define get_map(p)  (hblkmap[divHBLKSZ(((long)p) - ((long)heapstart))])
  1618. X# endif
  1619. X
  1620. X# ifdef INTERIOR_POINTERS
  1621. X  /* Return the word displacement of the beginning of the object to       */
  1622. X  /* which q points.  q is an address inside hblk p for objects of size s */
  1623. X  /* with mask m corresponding to s.                                      */
  1624. X#  define get_word_no(q,p,s,m) \
  1625. X        (((long)(m)) >= 0 ? \
  1626. X        (((((long)q) - ((long)p) - (sizeof (struct hblkhdr))) & ~(m)) \
  1627. X         + (sizeof (struct hblkhdr)) >> 2) \
  1628. X        : ((((long)q) - ((long)p) - (sizeof (struct hblkhdr)) >> 2) \
  1629. X           / (s)) * (s) \
  1630. X           + ((sizeof (struct hblkhdr)) >> 2))
  1631. X# else
  1632. X  /* Check whether q points to an object inside hblk p for objects of size s */
  1633. X  /* with mask m corresponding to s.                                         */
  1634. X#  define is_proper_obj(q,p,s,m) \
  1635. X        (((long)(m)) >= 0 ? \
  1636. X        (((((long)(q)) - (sizeof (struct hblkhdr))) & (m)) == 0) \
  1637. X        : (((long) (q)) - ((long)(p)) - (sizeof (struct hblkhdr))) \
  1638. X           % ((s) << 2) == 0)
  1639. X#  endif
  1640. X
  1641. X/* The following is a quick test whether something is an object pointer */
  1642. X/* It may err in the direction of identifying bogus pointers            */
  1643. X/* Assumes heap + text + data + bss < 64 Meg.                           */
  1644. X#ifdef M68K
  1645. X#   define TMP_POINTER_MASK 0xfc000003  /* pointer & POINTER_MASK should be 0 */
  1646. X#else
  1647. X# ifdef RT
  1648. X#   define TMP_POINTER_MASK 0xc0000003
  1649. X# else
  1650. X#   ifdef VAX
  1651. X#     define TMP_POINTER_MASK 0xfc000003
  1652. X#   else
  1653. X#     ifdef SPARC
  1654. X#       define TMP_POINTER_MASK 0xfc000003
  1655. X#     else
  1656. X#       ifdef I386
  1657. X#         define TMP_POINTER_MASK 0xfc000003
  1658. X#       else
  1659. X#         ifdef NS32K
  1660. X#           define TMP_POINTER_MASK 0xfc000003
  1661. X#         else
  1662. X#           ifdef MIPS
  1663. X#             define TMP_POINTER_MASK 0xc0000003
  1664. X#           else
  1665. X          --> dont know <--
  1666. X#           endif
  1667. X#         endif
  1668. X#       endif
  1669. X#     endif
  1670. X#   endif
  1671. X# endif
  1672. X#endif
  1673. X
  1674. X#ifdef INTERIOR_POINTERS
  1675. X#   define POINTER_MASK (TMP_POINTER_MASK & 0xfffffff8)
  1676. X    /* Don't pay attention to whether address is properly aligned */
  1677. X#else
  1678. X#   define POINTER_MASK TMP_POINTER_MASK
  1679. X#endif
  1680. X
  1681. X#ifdef HBLK_MAP
  1682. X#  define quicktest(p) (((long)(p)) > ((long)(heapstart)) \
  1683. X            && !(((unsigned long)(p)) & POINTER_MASK))
  1684. X#else
  1685. X# ifdef UNALIGNED
  1686. X#  define quicktest(p) (((long)(p)) > ((long)(&end)) \
  1687. X                        && !(((unsigned long)(p)) & POINTER_MASK) \
  1688. X                        && (((long)(p)) & HBLKMASK))
  1689. X    /* The last test throws out pointers to the beginning of heap */
  1690. X        /* blocks.  Small integers shifted by 16 bits tend to look    */
  1691. X        /* like these.                                                */
  1692. X# else
  1693. X#  define quicktest(p) (((long)(p)) > ((long)(&end)) \
  1694. X            && !(((unsigned long)(p)) & POINTER_MASK))
  1695. X# endif
  1696. X#endif
  1697. X
  1698. X
  1699. X/*  Marks are in a reserved area in                          */
  1700. X/*  each heap block.  Each word has one mark bits associated */
  1701. X/*  with it. Only those corresponding to the beginning of an */
  1702. X/*  object are used.                                         */
  1703. X
  1704. X
  1705. X/* Operations */
  1706. X
  1707. X/*
  1708. X * Retrieve, set, clear the mark bit corresponding
  1709. X * to the nth word in a given heap block.
  1710. X * Note that retrieval will work, so long as *hblk is addressable.
  1711. X * In particular, the check whether hblk is a legitimate heap block
  1712. X * can be postponed until after the mark bit is examined.
  1713. X *
  1714. X * (Recall that bit n corresponds to object beginning at word n)
  1715. X */
  1716. X
  1717. X# define mark_bit(hblk,n) (((hblk)->hb_marks[divWORDSZ(n)] \
  1718. X                >> (modWORDSZ(n))) & 1)
  1719. X
  1720. X/* The following assume the mark bit in question is either initially */
  1721. X/* cleared or it already has its final value                         */
  1722. X# define set_mark_bit(hblk,n) (hblk)->hb_marks[divWORDSZ(n)] \
  1723. X                |= 1 << modWORDSZ(n)
  1724. X
  1725. X# define clear_mark_bit(hblk,n) (hblk)->hb_marks[divWORDSZ(n)] \
  1726. X                &= ~(1 << modWORDSZ(n))
  1727. X
  1728. X/*  procedures */
  1729. X
  1730. X/* Small object allocation routines */
  1731. Xextern struct obj * allocobj();
  1732. Xextern struct obj * allocaobj();
  1733. X
  1734. X/* general purpose allocation routines */
  1735. Xextern struct obj * gc_malloc();
  1736. X
  1737. Xextern struct obj * gc_malloc_comp();
  1738. X
  1739. /
  1740. echo 'Distribution file ../gc.shar.01 complete.'
  1741.  
  1742.