1: /* Storage allocation and gc for GNU Emacs Lisp interpreter.
   2:    Copyright (C) 1985 Richard M. Stallman.
   3: 
   4: This file is part of GNU Emacs.
   5: 
   6: GNU Emacs is distributed in the hope that it will be useful,
   7: but WITHOUT ANY WARRANTY.  No author or distributor
   8: accepts responsibility to anyone for the consequences of using it
   9: or for whether it serves any particular purpose or works at all,
  10: unless he says so in writing.  Refer to the GNU Emacs General Public
  11: License for full details.
  12: 
  13: Everyone is granted permission to copy, modify and redistribute
  14: GNU Emacs, but only under the conditions described in the
  15: GNU Emacs General Public License.   A copy of this license is
  16: supposed to have been given to you along with GNU Emacs so you
  17: can know your rights and responsibilities.  It should be in a
  18: file named COPYING.  Among other things, the copyright notice
  19: and this notice must be preserved on all copies.  */
  20: 
  21: 
  22: #include "config.h"
  23: #include "lisp.h"
  24: #ifndef standalone
  25: #include "buffer.h"
  26: #include "window.h"
  27: #endif
  28: 
  29: /* Number of bytes of consing done since the last gc */
  30: int consing_since_gc;
  31: 
  32: /* Number of bytes of consing since gc before another gc should be done. */
  33: int gc_cons_threshold;
  34: 
  35: /* Nonzero during gc */
  36: int gc_in_progress;
  37: 
  38: #ifndef VIRT_ADDR_VARIES
  39: /* Address below which pointers should not be traced */
  40: extern char edata[];
  41: #endif /* VIRT_ADDR_VARIES */
  42: 
  43: #ifndef VIRT_ADDR_VARIES
  44: extern
  45: #endif /* VIRT_ADDR_VARIES */
  46:  int malloc_sbrk_used;
  47: 
  48: #ifndef VIRT_ADDR_VARIES
  49: extern
  50: #endif /* VIRT_ADDR_VARIES */
  51:  int malloc_sbrk_unused;
  52: 
  53: /* Non-nil means defun should do purecopy on the function definition */
  54: Lisp_Object Vpurify_flag;
  55: 
  56: int pure[PURESIZE / sizeof (int)] = {0,};   /* Force it into data space! */
  57: 
  58: #define PUREBEG (char *) pure
  59: 
  60: /* Index in pure at which next pure object will be allocated. */
  61: int pureptr;
  62: 
  63: Lisp_Object
  64: malloc_warning_1 (str)
  65:      Lisp_Object str;
  66: {
  67:   return Fprinc (str, Vstandard_output);
  68: }
  69: 
  70: /* malloc calls this if it finds we are near exhausting storage */
  71: malloc_warning (str)
  72:      char *str;
  73: {
  74:   Lisp_Object val;
  75:   val = build_string (str);
  76:   internal_with_output_to_temp_buffer (" *Danger*", malloc_warning_1, val);
  77: }
  78: 
  79: /* Called if malloc returns zero */
  80: memory_full ()
  81: {
  82:   error ("Memory exhausted");
  83: }
  84: 
  85: /* like malloc and realloc but check for no memory left */
  86: 
  87: long *
  88: xmalloc (size)
  89:      int size;
  90: {
  91:   long *val = (long *) malloc (size);
  92:   if (!val) memory_full ();
  93:   return val;
  94: }
  95: 
  96: long *
  97: xrealloc (block, size)
  98:      long *block;
  99:      int size;
 100: {
 101:   long *val = (long *) realloc (block, size);
 102:   if (!val) memory_full ();
 103:   return val;
 104: }
 105: 
 106: /* Allocation of cons cells */
 107: /* We store cons cells inside of cons_blocks, allocating a new
 108:  cons_block with malloc whenever necessary.  Cons cells reclaimed by
 109:  GC are put on a free list to be reallocated before allocating
 110:  any new cons cells from the latest cons_block.
 111: 
 112:  Each cons_block is just under 1020 bytes long,
 113:  since malloc really allocates in units of powers of two
 114:  and uses 4 bytes for its own overhead. */
 115: 
 116: #define CONS_BLOCK_SIZE \
 117:   ((1020 - sizeof (struct cons_block *)) / sizeof (struct Lisp_Cons))
 118: 
 119: struct cons_block
 120:   {
 121:     struct cons_block *next;
 122:     struct Lisp_Cons conses[CONS_BLOCK_SIZE];
 123:   };
 124: 
 125: struct cons_block *cons_block;
 126: int cons_block_index;
 127: 
 128: struct Lisp_Cons *cons_free_list;
 129: 
 130: void
 131: init_cons ()
 132: {
 133:   cons_block = (struct cons_block *) malloc (sizeof (struct cons_block));
 134:   cons_block->next = 0;
 135:   bzero (cons_block->conses, sizeof cons_block->conses);
 136:   cons_block_index = 0;
 137:   cons_free_list = 0;
 138: }
 139: 
 140: /* Explicitly free a cons cell.  */
 141: free_cons (ptr)
 142:      struct Lisp_Cons *ptr;
 143: {
 144:   XSETCONS (ptr->car, cons_free_list);
 145:   cons_free_list = ptr;
 146: }
 147: 
 148: DEFUN ("cons", Fcons, Scons, 2, 2, 0,
 149:   "Create a new cons, give it CAR and CDR as components, and return it.")
 150:   (car, cdr)
 151:      Lisp_Object car, cdr;
 152: {
 153:   register Lisp_Object val;
 154: 
 155:   if (cons_free_list)
 156:     {
 157:       XSET (val, Lisp_Cons, cons_free_list);
 158:       cons_free_list = XCONS (cons_free_list->car);
 159:     }
 160:   else
 161:     {
 162:       if (cons_block_index == CONS_BLOCK_SIZE)
 163:     {
 164:       register struct cons_block *new = (struct cons_block *) malloc (sizeof (struct cons_block));
 165:       if (!new) memory_full ();
 166:       new->next = cons_block;
 167:       cons_block = new;
 168:       cons_block_index = 0;
 169:     }
 170:       XSET (val, Lisp_Cons, &cons_block->conses[cons_block_index++]);
 171:     }
 172:   XCONS (val)->car = car;
 173:   XCONS (val)->cdr = cdr;
 174:   consing_since_gc += sizeof (struct Lisp_Cons);
 175:   return val;
 176: }
 177: 
 178: DEFUN ("list", Flist, Slist, 0, MANY, 0,
 179:   "Return a newly created list whose elements are the arguments (any number).")
 180:   (nargs, args)
 181:      int nargs;
 182:      Lisp_Object *args;
 183: {
 184:   Lisp_Object len, val, val_tail;
 185: 
 186:   XFASTINT (len) = nargs;
 187:   val = Fmake_list (len, Qnil);
 188:   val_tail = val;
 189:   while (!NULL (val_tail))
 190:     {
 191:       XCONS (val_tail)->car = *args++;
 192:       val_tail = XCONS (val_tail)->cdr;
 193:     }
 194:   return val;
 195: }
 196: 
 197: DEFUN ("make-list", Fmake_list, Smake_list, 2, 2, 0,
 198:   "Return a newly created list of length LENGTH, with each element being INIT.")
 199:   (length, init)
 200:      Lisp_Object length, init;
 201: {
 202:   register Lisp_Object val;
 203:   register int size;
 204: 
 205:   if (XTYPE (length) != Lisp_Int || XINT (length) < 0)
 206:     length = wrong_type_argument (Qnatnump, length);
 207:   size = XINT (length);
 208: 
 209:   val = Qnil;
 210:   while (size-- > 0)
 211:     val = Fcons (init, val);
 212:   return val;
 213: }
 214: 
 215: /* Allocation of vectors */
 216: 
 217: struct Lisp_Vector *all_vectors;
 218: 
 219: DEFUN ("make-vector", Fmake_vector, Smake_vector, 2, 2, 0,
 220:   "Return a newly created vector of length LENGTH, with each element being INIT.")
 221:   (length, init)
 222:      Lisp_Object length, init;
 223: {
 224:   register int sizei, index;
 225:   register Lisp_Object vector;
 226: 
 227:   if (XTYPE (length) != Lisp_Int || XINT (length) < 0)
 228:     length = wrong_type_argument (Qnatnump, length);
 229:   sizei = XINT (length);
 230: 
 231:   XSET (vector, Lisp_Vector,
 232:     (struct Lisp_Vector *) malloc (sizeof (struct Lisp_Vector) + (sizei - 1) * sizeof (Lisp_Object)));
 233:   consing_since_gc += sizeof (struct Lisp_Vector) + (sizei - 1) * sizeof (Lisp_Object);
 234:   if (!XVECTOR (vector))
 235:     memory_full ();
 236: 
 237:   XVECTOR (vector)->size = sizei;
 238:   XVECTOR (vector)->next = all_vectors;
 239:   all_vectors = XVECTOR (vector);
 240: 
 241:   for (index = 0; index < sizei; index++)
 242:     XVECTOR (vector)->contents[index] = init;
 243: 
 244:   return vector;
 245: }
 246: 
 247: DEFUN ("vector", Fvector, Svector, 0, MANY, 0,
 248:   "Return a newly created vector with our arguments (any number) as its elements.")
 249:   (nargs, args)
 250:      int nargs;
 251:      Lisp_Object *args;
 252: {
 253:   register Lisp_Object len, val;
 254:   register int index;
 255:   register struct Lisp_Vector *p;
 256: 
 257:   XFASTINT (len) = nargs;
 258:   val = Fmake_vector (len, Qnil);
 259:   p = XVECTOR (val);
 260:   for (index = 0; index < nargs; index++)
 261:     p->contents[index] = args[index];
 262:   return val;
 263: }
 264: 
 265: /* Allocation of symbols.
 266:  Just like allocation of conses!
 267: 
 268:  Each symbol_block is just under 1020 bytes long,
 269:  since malloc really allocates in units of powers of two
 270:  and uses 4 bytes for its own overhead. */
 271: 
 272: #define SYMBOL_BLOCK_SIZE \
 273:   ((1020 - sizeof (struct symbol_block *)) / sizeof (struct Lisp_Symbol))
 274: 
 275: struct symbol_block
 276:   {
 277:     struct symbol_block *next;
 278:     struct Lisp_Symbol symbols[SYMBOL_BLOCK_SIZE];
 279:   };
 280: 
 281: struct symbol_block *symbol_block;
 282: int symbol_block_index;
 283: 
 284: struct Lisp_Symbol *symbol_free_list;
 285: 
 286: void
 287: init_symbol ()
 288: {
 289:   symbol_block = (struct symbol_block *) malloc (sizeof (struct symbol_block));
 290:   symbol_block->next = 0;
 291:   bzero (symbol_block->symbols, sizeof symbol_block->symbols);
 292:   symbol_block_index = 0;
 293:   symbol_free_list = 0;
 294: }
 295: 
 296: DEFUN ("make-symbol", Fmake_symbol, Smake_symbol, 1, 1, 0,
 297:   "Return a newly allocated uninterned symbol whose name is NAME.\n\
 298: Its value and function definition are void, and its property list is NIL.")
 299:   (str)
 300:      Lisp_Object str;
 301: {
 302:   register Lisp_Object val;
 303: 
 304:   CHECK_STRING (str, 0);
 305: 
 306:   if (symbol_free_list)
 307:     {
 308:       XSET (val, Lisp_Symbol, symbol_free_list);
 309:       symbol_free_list = XSYMBOL (symbol_free_list->value);
 310:     }
 311:   else
 312:     {
 313:       if (symbol_block_index == SYMBOL_BLOCK_SIZE)
 314:     {
 315:       struct symbol_block *new = (struct symbol_block *) malloc (sizeof (struct symbol_block));
 316:       if (!new) memory_full ();
 317:       new->next = symbol_block;
 318:       symbol_block = new;
 319:       symbol_block_index = 0;
 320:     }
 321:       XSET (val, Lisp_Symbol, &symbol_block->symbols[symbol_block_index++]);
 322:     }
 323:   XSYMBOL (val)->name = XSTRING (str);
 324:   XSYMBOL (val)->plist = Qnil;
 325:   XSYMBOL (val)->value = Qunbound;
 326:   XSYMBOL (val)->function = Qunbound;
 327:   XSYMBOL (val)->next = 0;
 328:   consing_since_gc += sizeof (struct Lisp_Symbol);
 329:   return val;
 330: }
 331: 
 332: /* Allocation of markers.
 333:  Works like allocation of conses. */
 334: 
 335: #define MARKER_BLOCK_SIZE \
 336:   ((1020 - sizeof (struct marker_block *)) / sizeof (struct Lisp_Marker))
 337: 
 338: struct marker_block
 339:   {
 340:     struct marker_block *next;
 341:     struct Lisp_Marker markers[MARKER_BLOCK_SIZE];
 342:   };
 343: 
 344: struct marker_block *marker_block;
 345: int marker_block_index;
 346: 
 347: struct Lisp_Marker *marker_free_list;
 348: 
 349: void
 350: init_marker ()
 351: {
 352:   marker_block = (struct marker_block *) malloc (sizeof (struct marker_block));
 353:   marker_block->next = 0;
 354:   bzero (marker_block->markers, sizeof marker_block->markers);
 355:   marker_block_index = 0;
 356:   marker_free_list = 0;
 357: }
 358: 
 359: DEFUN ("make-marker", Fmake_marker, Smake_marker, 0, 0, 0,
 360:   "Return a newly allocated marker which does not point at any place.")
 361:   ()
 362: {
 363:   register Lisp_Object val;
 364: 
 365:   if (marker_free_list)
 366:     {
 367:       XSET (val, Lisp_Marker, marker_free_list);
 368:       marker_free_list = XMARKER (marker_free_list->chain);
 369:     }
 370:   else
 371:     {
 372:       if (marker_block_index == MARKER_BLOCK_SIZE)
 373:     {
 374:       struct marker_block *new = (struct marker_block *) malloc (sizeof (struct marker_block));
 375:       if (!new) memory_full ();
 376:       new->next = marker_block;
 377:       marker_block = new;
 378:       marker_block_index = 0;
 379:     }
 380:       XSET (val, Lisp_Marker, &marker_block->markers[marker_block_index++]);
 381:     }
 382:   XMARKER (val)->buffer = 0;
 383:   XMARKER (val)->bufpos = 0;
 384:   XMARKER (val)->modified = 0;
 385:   XMARKER (val)->chain = Qnil;
 386:   consing_since_gc += sizeof (struct Lisp_Marker);
 387:   return val;
 388: }
 389: 
 390: /* Allocation of strings */
 391: 
 392: /* Strings reside inside of string_blocks.  The entire data of the string,
 393:  both the size and the contents, live in part of the `chars' component of a string_block.
 394:  The `pos' component is the index within `chars' of the first free byte */
 395: 
 396: /* String blocks contain this many bytes.
 397:   Power of 2, minus 4 for malloc overhead. */
 398: #define STRING_BLOCK_SIZE (8188 - sizeof (struct string_block_head))
 399: 
 400: /* A string bigger than this gets its own specially-made string block
 401:  if it doesn't fit in the current one. */
 402: #define STRING_BLOCK_OUTSIZE 1024
 403: 
 404: struct string_block_head
 405:   {
 406:     struct string_block *next;
 407:     int pos;
 408:   };
 409: 
 410: struct string_block
 411:   {
 412:     struct string_block *next;
 413:     int pos;
 414:     char chars[STRING_BLOCK_SIZE];
 415:   };
 416: 
 417: /* This points to the string block we are now allocating strings in
 418:  which is also the beginning of the chain of all string blocks ever made */
 419: 
 420: struct string_block *current_string_block;
 421: 
 422: void
 423: init_strings ()
 424: {
 425:   current_string_block = (struct string_block *) malloc (sizeof (struct string_block));
 426:   consing_since_gc += sizeof (struct string_block);
 427:   current_string_block->next = 0;
 428:   current_string_block->pos = 0;
 429: }
 430: 
 431: static Lisp_Object make_zero_string ();
 432: 
 433: DEFUN ("make-string", Fmake_string, Smake_string, 2, 2, 0,
 434:   "Return a newly created string of length LENGTH, with each element being INIT.\n\
 435: Both LENGTH and INIT must be numbers.")
 436:   (length, init)
 437:      Lisp_Object length, init;
 438: {
 439:   if (XTYPE (length) != Lisp_Int || XINT (length) < 0)
 440:     length = wrong_type_argument (Qnatnump, length);
 441:   CHECK_NUMBER (init, 1);
 442:   return make_zero_string (XINT (length), XINT (init));
 443: }
 444: 
 445: Lisp_Object
 446: make_string (contents, length)
 447:      char *contents;
 448:      int length;
 449: {
 450:   Lisp_Object val;
 451:   val = make_zero_string (length, 0);
 452:   bcopy (contents, XSTRING (val)->data, length);
 453:   return val;
 454: }
 455: 
 456: Lisp_Object
 457: build_string (str)
 458:      char *str;
 459: {
 460:   return make_string (str, strlen (str));
 461: }
 462: 
 463: static Lisp_Object
 464: make_zero_string (length, init)
 465:      int length;
 466:      register int init;
 467: {
 468:   register Lisp_Object val;
 469:   register int fullsize = length + sizeof (int);
 470:   register unsigned char *p, *end;
 471: 
 472:   if (length < 0) abort ();
 473: 
 474:   /* Round `fullsize' up to multiple of size of int; also add one for terminating zero */
 475:   fullsize += sizeof (int);
 476:   fullsize &= ~(sizeof (int) - 1);
 477: 
 478:   if (fullsize <= STRING_BLOCK_SIZE - current_string_block->pos)
 479:     /* This string can fit in the current string block */
 480:     {
 481:       XSET (val, Lisp_String,
 482:         (struct Lisp_String *) (current_string_block->chars + current_string_block->pos));
 483:       current_string_block->pos += fullsize;
 484:     }
 485:   else if (fullsize > STRING_BLOCK_OUTSIZE)
 486:     /* This string gets its own string block */
 487:     {
 488:       struct string_block *new = (struct string_block *) malloc (sizeof (struct string_block_head) + fullsize);
 489:       if (!new) memory_full ();
 490:       consing_since_gc += sizeof (struct string_block_head) + fullsize;
 491:       new->pos = fullsize;
 492:       new->next = current_string_block->next;
 493:       current_string_block->next = new;
 494:       XSET (val, Lisp_String,
 495:         (struct Lisp_String *) ((struct string_block_head *)new + 1));
 496:     }
 497:   else
 498:     /* Make a new current string block and start it off with this string */
 499:     {
 500:       struct string_block *new = (struct string_block *) malloc (sizeof (struct string_block));
 501:       if (!new) memory_full ();
 502:       consing_since_gc += sizeof (struct string_block);
 503:       new->next = current_string_block;
 504:       current_string_block = new;
 505:       new->pos = fullsize;
 506:       XSET (val, Lisp_String,
 507:         (struct Lisp_String *) current_string_block->chars);
 508:     }
 509: 
 510:   XSTRING (val)->size = length;
 511:   p = XSTRING (val)->data;
 512:   end = p + XSTRING (val)->size;
 513:   while (p != end)
 514:     *p++ = init;
 515:   *p = 0;
 516: 
 517:   return val;
 518: }
 519: 
 520: /* Must get an error if pure storage is full,
 521:  since if it cannot hold a large string
 522:  it may be able to hold conses that point to that string;
 523:  then the string is not protected from gc. */
 524: 
 525: Lisp_Object
 526: make_pure_string (data, length)
 527:      char *data;
 528:      int length;
 529: {
 530:   Lisp_Object new;
 531:   int size = sizeof (int) + length + 1;
 532: 
 533:   if (pureptr + size > PURESIZE)
 534:     error ("Pure Lisp storage exhausted");
 535:   XSET (new, Lisp_String, PUREBEG + pureptr);
 536:   XSTRING (new)->size = length;
 537:   bcopy (data, XSTRING (new)->data, length);
 538:   XSTRING (new)->data[length] = 0;
 539:   pureptr += (size + sizeof (int) - 1)
 540:          / sizeof (int) * sizeof (int);
 541:   return new;
 542: }
 543: 
 544: Lisp_Object
 545: pure_cons (car, cdr)
 546:      Lisp_Object car, cdr;
 547: {
 548:   Lisp_Object new;
 549: 
 550:   if (pureptr + sizeof (struct Lisp_Cons) > PURESIZE)
 551:     error ("Pure Lisp storage exhausted");
 552:   XSET (new, Lisp_Cons, PUREBEG + pureptr);
 553:   pureptr += sizeof (struct Lisp_Cons);
 554:   XCONS (new)->car = Fpurecopy (car);
 555:   XCONS (new)->cdr = Fpurecopy (cdr);
 556:   return new;
 557: }
 558: 
 559: Lisp_Object
 560: make_pure_vector (len)
 561:      int len;
 562: {
 563:   Lisp_Object new;
 564:   int size = sizeof (struct Lisp_Vector) + (len - 1) * sizeof (Lisp_Object);
 565: 
 566:   if (pureptr + size > PURESIZE)
 567:     error ("Pure Lisp storage exhausted");
 568: 
 569:   XSET (new, Lisp_Vector, PUREBEG + pureptr);
 570:   pureptr += size;
 571:   XVECTOR (new)->size = len;
 572:   return new;
 573: }
 574: 
 575: DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
 576:   "Make a copy of OBJECT in pure storage.\n\
 577: Recursively copies contents of vectors and cons cells.\n\
 578: Does not copy symbols.")
 579:   (obj)
 580:      Lisp_Object obj;
 581: {
 582:   Lisp_Object new, tem;
 583:   int i;
 584: 
 585: #ifndef VIRT_ADDR_VARIES
 586:   /* Need not trace pointers to pure storage */
 587:   if (XUINT (obj) < (unsigned int) edata && XUINT (obj) >= 0)
 588:     return obj;
 589: #else /* VIRT_ADDR_VARIES */
 590:   if (XUINT (obj) < (unsigned int) ((char *) pure + PURESIZE)
 591:       && XUINT (obj) >= (unsigned int) pure)
 592:     return obj;
 593: #endif /* VIRT_ADDR_VARIES */
 594: 
 595: #ifdef SWITCH_ENUM_BUG
 596:   switch ((int) XTYPE (obj))
 597: #else
 598:   switch (XTYPE (obj))
 599: #endif
 600:     {
 601:     case Lisp_Marker:
 602:       error ("Attempt to copy a marker to pure storage");
 603: 
 604:     case Lisp_Cons:
 605:       return pure_cons (XCONS (obj)->car, XCONS (obj)->cdr);
 606: 
 607:     case Lisp_String:
 608:       return make_pure_string (XSTRING (obj)->data, XSTRING (obj)->size);
 609: 
 610:     case Lisp_Vector:
 611:       new = make_pure_vector (XVECTOR (obj)->size);
 612:       for (i = 0; i < XVECTOR (obj)->size; i++)
 613:     {
 614:       tem = XVECTOR (obj)->contents[i];
 615:       XVECTOR (new)->contents[i] = Fpurecopy (tem);
 616:     }
 617:       return new;
 618: 
 619:     default:
 620:       return obj;
 621:     }
 622: }
 623: 
 624: /* Recording what needs to be marked for gc.  */
 625: 
 626: struct gcpro *gcprolist;
 627: 
 628: #define NSTATICS 100
 629: 
 630: char staticvec1[NSTATICS * sizeof (Lisp_Object *)] = {0};
 631: 
 632: int staticidx = 0;
 633: 
 634: #define staticvec ((Lisp_Object **) staticvec1)
 635: 
 636: /* Put an entry in staticvec, pointing at the variable whose address is given */
 637: 
 638: void
 639: staticpro (varaddress)
 640:      Lisp_Object *varaddress;
 641: {
 642:   staticvec[staticidx++] = varaddress;
 643:   if (staticidx >= NSTATICS)
 644:     abort ();
 645: }
 646: 
 647: struct catchtag
 648:   {
 649:     Lisp_Object tag;
 650:     Lisp_Object val;
 651:     struct catchtag *next;
 652: /*    jmp_buf jmp;  /* We don't need this for GC purposes */
 653:   };
 654: 
 655: extern struct catchtag *catchlist;
 656: 
 657: struct backtrace
 658:   {
 659:     struct backtrace *next;
 660:     Lisp_Object *function;
 661:     Lisp_Object *args;  /* Points to vector of args. */
 662:     int nargs;      /* length of vector */
 663:            /* if nargs is UNEVALLED, args points to slot holding list of unevalled args */
 664:     char evalargs;
 665:   };
 666: 
 667: extern struct backtrace *backtrace_list;
 668: 
 669: /* On vector, means it has been marked.
 670:  On string, means it has been copied.  */
 671: static int most_negative_fixnum;
 672: 
 673: /* On string, means do not copy it.
 674:  This is set in all copies, and perhaps will be used
 675:  to indicate strings that there is no need to copy.  */
 676: static int dont_copy_flag;
 677: 
 678: int total_conses, total_markers, total_symbols, total_string_size, total_vector_size;
 679: int total_free_conses, total_free_markers, total_free_symbols;
 680: 
 681: /* Garbage collection: mark and sweep, except copy strings. */
 682: static Lisp_Object mark_object ();
 683: static void clear_marks (), gc_sweep ();
 684: 
 685: DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "",
 686:   "Reclaim storage for Lisp objects no longer needed.\n\
 687: Returns info on amount of space in use:\n\
 688:  ((USED-CONSES . FREE-CONSES) (USED-SYMS . FREE-SYMS)\n\
 689:   (USED-MARKERS . FREE-MARKERS) USED-STRING-CHARS USED-VECTOR-SLOTS)\n\
 690: Garbage collection happens automatically if you cons more than\n\
 691: gc-cons-threshold  bytes of Lisp data since previous garbage collection.")
 692:   ()
 693: {
 694:   struct string_block *old_string_block;
 695: 
 696:   register struct gcpro *tail;
 697:   register struct specbinding *bind;
 698:   struct catchtag *catch;
 699:   struct handler *handler;
 700:   register struct backtrace *backlist;
 701:   register Lisp_Object tem;
 702:   char *omessage = minibuf_message;
 703: 
 704:   register int i;
 705: 
 706:   if (!noninteractive)
 707:     message1 ("Garbage collecting...");
 708: 
 709:   /* Don't keep command history around forever */
 710:   tem = Fnthcdr (make_number (30), Vcommand_history);
 711:   if (LISTP (tem))
 712:     XCONS (tem)->cdr = Qnil;
 713: 
 714:   gc_in_progress = 1;
 715: 
 716:   clear_marks ();
 717:   old_string_block = current_string_block;
 718:   current_string_block = 0;
 719:   total_string_size = 0;
 720:   init_strings ();
 721: 
 722:   for (tail = gcprolist; tail; tail = tail->next)
 723:     {
 724:       for (i = 0; i < tail->nvars; i++)
 725:     {
 726:       tem = tail->var[i];
 727:       tail->var[i] = mark_object (tem);
 728:     }
 729:     }
 730:   for (i = 0; i < staticidx; i++)
 731:     {
 732:       tem = *staticvec[i];
 733:       *staticvec[i] = mark_object (tem);
 734:     }
 735:   for (bind = specpdl; bind != specpdl_ptr; bind++)
 736:     {
 737:       bind->symbol = mark_object (bind->symbol);
 738:       bind->old_value = mark_object (bind->old_value);
 739:     }
 740:   for (catch = catchlist; catch; catch = catch->next)
 741:     {
 742:       catch->tag = mark_object (catch->tag);
 743:       catch->val = mark_object (catch->val);
 744:     }
 745:   for (handler = handlerlist; handler; handler = handler->next)
 746:     {
 747:       handler->handler = mark_object (handler->handler);
 748:       handler->var = mark_object (handler->var);
 749:     }
 750:   for (backlist = backtrace_list; backlist; backlist = backlist->next)
 751:     {
 752:       tem = *backlist->function;
 753:       *backlist->function = mark_object (tem);
 754:       if (backlist->nargs == UNEVALLED || backlist->nargs == MANY)
 755:     {
 756:       tem = *backlist->args;
 757:       *backlist->args = mark_object (tem);
 758:     }
 759:       else
 760:     for (i = 0; i < backlist->nargs; i++)
 761:       {
 762:         tem = backlist->args[i];
 763:         backlist->args[i] = mark_object (tem);
 764:       }
 765:     }
 766: 
 767:   gc_sweep (old_string_block);
 768: 
 769:   clear_marks ();
 770:   gc_in_progress = 0;
 771: 
 772:   consing_since_gc = 0;
 773:   if (gc_cons_threshold < 10000)
 774:     gc_cons_threshold = 10000;
 775: 
 776:   if (omessage)
 777:     message1 (omessage);
 778:   else if (!noninteractive)
 779:     message1 ("Garbage collecting...done");
 780: 
 781:   return Fcons (Fcons (make_number (total_conses),
 782:                make_number (total_free_conses)),
 783:         Fcons (Fcons (make_number (total_symbols),
 784:                   make_number (total_free_symbols)),
 785:                Fcons (Fcons (make_number (total_markers),
 786:                      make_number (total_free_markers)),
 787:                   Fcons (make_number (total_string_size),
 788:                      Fcons (make_number (total_vector_size),
 789:                         Qnil)))));
 790: }
 791: 
 792: static void
 793: clear_marks ()
 794: {
 795:   /* Clear marks on all strings */
 796:   {
 797:     register struct string_block *csb;
 798:     register int pos;
 799: 
 800:     for (csb = current_string_block; csb; csb = csb->next)
 801:       {
 802:     pos = 0;
 803:     while (pos < csb->pos)
 804:       {
 805:         register struct Lisp_String *nextstr
 806:           = (struct Lisp_String *) &csb->chars[pos];
 807:         register int fullsize;
 808: 
 809:         nextstr->size &= ~dont_copy_flag;
 810:         fullsize = nextstr->size + sizeof (int);
 811: 
 812:         fullsize += sizeof (int);
 813:         fullsize &= ~(sizeof (int) - 1);
 814:         pos += fullsize;
 815:       }
 816:       }
 817:   }
 818:   /* Clear marks on all conses */
 819:   {
 820:     register struct cons_block *cblk;
 821:     register int lim = cons_block_index;
 822: 
 823:     for (cblk = cons_block; cblk; cblk = cblk->next)
 824:       {
 825:     register int i;
 826:     for (i = 0; i < lim; i++)
 827:       XUNMARK (cblk->conses[i].car);
 828:     lim = CONS_BLOCK_SIZE;
 829:       }
 830:   }
 831:   /* Clear marks on all symbols */
 832:   {
 833:     register struct symbol_block *sblk;
 834:     register int lim = symbol_block_index;
 835: 
 836:     for (sblk = symbol_block; sblk; sblk = sblk->next)
 837:       {
 838:     register int i;
 839:     for (i = 0; i < lim; i++)
 840:       XUNMARK (sblk->symbols[i].plist);
 841:     lim = SYMBOL_BLOCK_SIZE;
 842:       }
 843:   }
 844:   /* Clear marks on all markers */
 845:   {
 846:     register struct marker_block *sblk;
 847:     register int lim = marker_block_index;
 848: 
 849:     for (sblk = marker_block; sblk; sblk = sblk->next)
 850:       {
 851:     register int i;
 852:     for (i = 0; i < lim; i++)
 853:       XUNMARK (sblk->markers[i].chain);
 854:     lim = MARKER_BLOCK_SIZE;
 855:       }
 856:   }
 857:   /* Clear mark bits on all buffers */
 858:   {
 859:     register struct buffer *nextb = all_buffers;
 860: 
 861:     while (nextb)
 862:       {
 863:     XUNMARK (nextb->name);
 864:     nextb = nextb->next;
 865:       }
 866:   }
 867: }
 868: 
 869: /* Mark one Lisp object, and recursively mark all the objects it points to
 870:  if this is the first time it is being marked.
 871:  If the object is a string, it is copied (once, only) and the copy is returned.
 872:  The original string's `size' is set to a value in which 1<<31 is set
 873:    and the rest of which is the string address shifted right by one.
 874:  If the object is not a string, it is returned unchanged. */
 875: 
 876: static Lisp_Object
 877: mark_object (obj)
 878:      Lisp_Object obj;
 879: {
 880:   Lisp_Object original;
 881: 
 882:   original = obj;
 883: 
 884:  loop:
 885: #ifndef VIRT_ADDR_VARIES
 886:   /* Need not trace pointers to pure storage */
 887:   if (XUINT (obj) < (unsigned int) edata && XUINT (obj) >= 0)
 888:     return original;
 889: #else /* VIRT_ADDR_VARIES */
 890:   if (XUINT (obj) < (unsigned int) ((char *) pure + PURESIZE)
 891:       && XUINT (obj) >= (unsigned int) pure)
 892:     return original;
 893: #endif /* VIRT_ADDR_VARIES */
 894: 
 895: #ifdef SWITCH_ENUM_BUG
 896:   switch ((int) XGCTYPE (obj))
 897: #else
 898:   switch (XGCTYPE (obj))
 899: #endif
 900:     {
 901:     case Lisp_String:
 902:       {
 903:     register struct Lisp_String *ptr = XSTRING (obj);
 904:     Lisp_Object tem;
 905: 
 906:     if (ptr->size & most_negative_fixnum)
 907:       {
 908:         XSETSTRING (obj, (struct Lisp_String *) (ptr->size & ~most_negative_fixnum));
 909:         return obj;
 910:       }
 911:     if (ptr->size & dont_copy_flag)
 912:       return obj;
 913:     total_string_size += ptr->size;
 914:     tem = make_string (ptr->data, ptr->size);
 915:     ptr->size = most_negative_fixnum | XINT (tem);
 916:     XSTRING (tem)->size |= dont_copy_flag;
 917:     return tem;
 918:       }
 919: 
 920:     case Lisp_Vector:
 921:     case Lisp_Window:
 922:     case Lisp_Process:
 923:       {
 924:     register struct Lisp_Vector *ptr = XVECTOR (obj);
 925:     register int size = ptr->size;
 926:     register int i;
 927:     Lisp_Object tem;
 928: 
 929:     if (size & most_negative_fixnum) break;   /* Already marked */
 930:     ptr->size |= most_negative_fixnum; /* Else mark it */
 931:     for (i = 0; i < size; i++)     /* and then mark its elements */
 932:       {
 933:         tem = ptr->contents[i];
 934:         ptr->contents[i] = mark_object (tem);
 935:       }
 936:       }
 937:       break;
 938: 
 939:     case Lisp_Temp_Vector:
 940:       {
 941:     register struct Lisp_Vector *ptr = XVECTOR (obj);
 942:     register int size = ptr->size;
 943:     register int i;
 944:     Lisp_Object tem;
 945: 
 946:     for (i = 0; i < size; i++)     /* and then mark its elements */
 947:       {
 948:         tem = ptr->contents[i];
 949:         ptr->contents[i] = mark_object (tem);
 950:       }
 951:       }
 952:       break;
 953: 
 954:     case Lisp_Symbol:
 955:       {
 956:     register struct Lisp_Symbol *ptr = XSYMBOL (obj);
 957:     struct Lisp_Symbol *ptrx;
 958:     Lisp_Object tem;
 959: 
 960:     if (XMARKBIT (ptr->plist)) break;
 961:     XMARK (ptr->plist);
 962:     XSET (tem, Lisp_String, ptr->name);
 963:     tem = mark_object (tem);
 964:     ptr->name = XSTRING (tem);
 965:     ptr->value = mark_object (ptr->value);
 966:     ptr->function = mark_object (ptr->function);
 967:     tem = ptr->plist;
 968:     XUNMARK (tem);
 969:     ptr->plist = mark_object (tem);
 970:     XMARK (ptr->plist);
 971:     ptr = ptr->next;
 972:     if (ptr)
 973:       {
 974:         ptrx = ptr;     /* Use pf ptrx avoids compiled bug on Sun */
 975:         XSETSYMBOL (obj, ptrx);
 976:         goto loop;
 977:       }
 978:       }
 979:       break;
 980: 
 981:     case Lisp_Marker:
 982:       XMARK (XMARKER (obj)->chain);
 983:       /* DO NOT mark thru the marker's chain.
 984: 	 The buffer's markers chain does not preserve markers from gc;
 985: 	 instead, markers are removed from the chain when they are freed by gc. */
 986:       break;
 987: 
 988:     case Lisp_Cons:
 989:     case Lisp_Buffer_Local_Value:
 990:     case Lisp_Some_Buffer_Local_Value:
 991:       {
 992:     Lisp_Object tem;
 993:     register struct Lisp_Cons *ptr = XCONS (obj);
 994:     if (XMARKBIT (ptr->car)) break;
 995:     tem = ptr->car;
 996:     XMARK (ptr->car);
 997:     ptr->car = mark_object (tem);
 998:     XMARK (ptr->car);
 999:     if (XGCTYPE (ptr->cdr) != Lisp_String)
1000:       {
1001:         obj = ptr->cdr;
1002:         goto loop;
1003:       }
1004:     ptr->cdr = mark_object (ptr->cdr);
1005:       }
1006:       break;
1007: 
1008:     case Lisp_Objfwd:
1009:       *XOBJFWD (obj) = mark_object (*XOBJFWD (obj));
1010:       break;
1011: 
1012:     case Lisp_Buffer:
1013:       if (!XMARKBIT (XBUFFER (obj)->name))
1014:     mark_buffer (obj);
1015:       break;
1016: 
1017:     /* Don't bother with Lisp_Buffer_Objfwd,
1018:        since all markable slots in current buffer marked anyway.  */
1019:     }
1020:   return original;
1021: }
1022: 
1023: /* Mark the pointers in a buffer structure.  */
1024: 
1025: mark_buffer (buf)
1026:      Lisp_Object buf;
1027: {
1028:   Lisp_Object tem;
1029:   register struct buffer *buffer = XBUFFER (buf);
1030: 
1031:   buffer->number = mark_object (buffer->number);
1032:   buffer->name = mark_object (buffer->name);
1033:   XMARK (buffer->name);
1034:   buffer->filename = mark_object (buffer->filename);
1035:   buffer->directory = mark_object (buffer->directory);
1036:   buffer->save_length = mark_object (buffer->save_length);
1037:   buffer->auto_save_file_name = mark_object (buffer->auto_save_file_name);
1038:   buffer->read_only = mark_object (buffer->read_only);
1039:   /* buffer->markers does not preserve from gc: scavenger removes marker from
1040:      the markers chain if it is freed.  See gc_sweep */
1041:   buffer->mark = mark_object (buffer->mark);
1042:   buffer->major_mode = mark_object (buffer->major_mode);
1043:   buffer->mode_name = mark_object (buffer->mode_name);
1044:   buffer->mode_line_format = mark_object (buffer->mode_line_format);
1045:   buffer->keymap = mark_object (buffer->keymap);
1046:   XSET (tem, Lisp_Vector, buffer->syntax_table_v);
1047:   if (buffer->syntax_table_v)
1048:     mark_object (tem);
1049:   buffer->abbrev_table = mark_object (buffer->abbrev_table);
1050:   buffer->case_fold_search = mark_object (buffer->case_fold_search);
1051:   buffer->tab_width = mark_object (buffer->tab_width);
1052:   buffer->fill_column = mark_object (buffer->fill_column);
1053:   buffer->left_margin = mark_object (buffer->left_margin);
1054:   buffer->auto_fill_hook = mark_object (buffer->auto_fill_hook);
1055:   buffer->local_var_alist = mark_object (buffer->local_var_alist);
1056:   buffer->truncate_lines = mark_object (buffer->truncate_lines);
1057:   buffer->ctl_arrow = mark_object (buffer->ctl_arrow);
1058:   buffer->selective_display = mark_object (buffer->selective_display);
1059:   buffer->minor_modes = mark_object (buffer->minor_modes);
1060:   buffer->overwrite_mode = mark_object (buffer->overwrite_mode);
1061:   buffer->abbrev_mode = mark_object (buffer->abbrev_mode);
1062: 
1063: }
1064: 
1065: /* Find all structures not marked, and free them. */
1066: 
1067: static void
1068: gc_sweep (old_string_block)
1069:      struct string_block *old_string_block;
1070: {
1071:   /* Put all unmarked conses on free list */
1072:   {
1073:     register struct cons_block *cblk;
1074:     register int lim = cons_block_index;
1075:     register int num_free = 0, num_used = 0;
1076: 
1077:     cons_free_list = 0;
1078: 
1079:     for (cblk = cons_block; cblk; cblk = cblk->next)
1080:       {
1081:     register int i;
1082:     for (i = 0; i < lim; i++)
1083:       if (!XMARKBIT (cblk->conses[i].car))
1084:         {
1085:           XSETCONS (cblk->conses[i].car, cons_free_list);
1086:           num_free++;
1087:           cons_free_list = &cblk->conses[i];
1088:         }
1089:       else num_used++;
1090:     lim = CONS_BLOCK_SIZE;
1091:       }
1092:     total_conses = num_used;
1093:     total_free_conses = num_free;
1094:   }
1095: 
1096:   /* Put all unmarked symbols on free list */
1097:   {
1098:     register struct symbol_block *sblk;
1099:     register int lim = symbol_block_index;
1100:     register int num_free = 0, num_used = 0;
1101: 
1102:     symbol_free_list = 0;
1103: 
1104:     for (sblk = symbol_block; sblk; sblk = sblk->next)
1105:       {
1106:     register int i;
1107:     for (i = 0; i < lim; i++)
1108:       if (!XMARKBIT (sblk->symbols[i].plist))
1109:         {
1110:           XSETSYMBOL (sblk->symbols[i].value, symbol_free_list);
1111:           symbol_free_list = &sblk->symbols[i];
1112:           num_free++;
1113:         }
1114:       else num_used++;
1115:     lim = SYMBOL_BLOCK_SIZE;
1116:       }
1117:     total_symbols = num_used;
1118:     total_free_symbols = num_free;
1119:   }
1120: 
1121: #ifndef standalone
1122:   /* Put all unmarked markers on free list.
1123:      Dechain each one first from the buffer it points into. */
1124:   {
1125:     register struct marker_block *mblk;
1126:     struct Lisp_Marker *tem1;
1127:     register int lim = marker_block_index;
1128:     register int num_free = 0, num_used = 0;
1129: 
1130:     marker_free_list = 0;
1131: 
1132:     for (mblk = marker_block; mblk; mblk = mblk->next)
1133:       {
1134:     register int i;
1135:     for (i = 0; i < lim; i++)
1136:       if (!XMARKBIT (mblk->markers[i].chain))
1137:         {
1138:           Lisp_Object tem;
1139:           tem1 = &mblk->markers[i];  /* tem1 avoids Sun compiler bug */
1140:           XSET (tem, Lisp_Marker, tem1);
1141:           unchain_marker (tem);
1142:           XSETMARKER (mblk->markers[i].chain, marker_free_list);
1143:           marker_free_list = &mblk->markers[i];
1144:           num_free++;
1145:         }
1146:       else num_used++;
1147:     lim = MARKER_BLOCK_SIZE;
1148:       }
1149: 
1150:     total_markers = num_used;
1151:     total_free_markers = num_free;
1152:   }
1153: 
1154:   /* Free all unmarked buffers */
1155:   {
1156:     register struct buffer *buffer = all_buffers, *prev = 0, *next = 0;
1157: 
1158:     while (buffer)
1159:       if (!XMARKBIT (buffer->name))
1160:     {
1161:       if (prev)
1162:         prev->next = buffer->next;
1163:       else
1164:         all_buffers = buffer->next;
1165:       next = buffer->next;
1166:       free (buffer);
1167:       buffer = next;
1168:     }
1169:       else
1170:     {
1171:       XUNMARK (buffer->name);
1172:       prev = buffer, buffer = buffer->next;
1173:     }
1174:   }
1175: 
1176: #endif standalone
1177: 
1178:   /* Free all unmarked vectors */
1179:   {
1180:     register struct Lisp_Vector *vector = all_vectors, *prev = 0, *next = 0;
1181:     total_vector_size = 0;
1182: 
1183:     while (vector)
1184:       if (!(vector->size & most_negative_fixnum))
1185:     {
1186:       if (prev)
1187:         prev->next = vector->next;
1188:       else
1189:         all_vectors = vector->next;
1190:       next = vector->next;
1191:       free (vector);
1192:       vector = next;
1193:     }
1194:       else
1195:     {
1196:       vector->size &= ~most_negative_fixnum;
1197:       total_vector_size += vector->size;
1198:       prev = vector, vector = vector->next;
1199:     }
1200:   }
1201: 
1202:   /* Free all old string blocks, since all strings still used have been copied. */
1203:   {
1204:     register struct string_block *sblk = old_string_block;
1205:     while (sblk)
1206:       {
1207:     struct string_block *next = sblk->next;
1208:     free (sblk);
1209:     sblk = next;
1210:       }
1211:   }
1212: }
1213: 
1214: /* Initialization */
1215: 
1216: init_alloc_once ()
1217: {
1218:   register int i, x;
1219:   /* Compute an int in which only the sign bit is set.  */
1220:   for (i = 0, x = 1; (x <<= 1) & ~1; i++)
1221:     /*empty loop*/;
1222:   most_negative_fixnum = 1 << i;
1223:   dont_copy_flag = 1 << (i - 1);
1224: 
1225:   Vpurify_flag = Qt;
1226: 
1227:   pureptr = 0;
1228:   all_vectors = 0;
1229:   init_strings ();
1230:   init_cons ();
1231:   init_symbol ();
1232:   init_marker ();
1233:   gcprolist = 0;
1234:   staticidx = 0;
1235:   consing_since_gc = 0;
1236:   gc_cons_threshold = 100000;
1237: #ifdef VIRT_ADDR_VARIES
1238:   malloc_sbrk_unused = 1<<22;   /* A large number */
1239:   malloc_sbrk_used = 100000;    /* as reasonable as any number */
1240: #endif /* VIRT_ADDR_VARIES */
1241: }
1242: 
1243: init_alloc ()
1244: {
1245:   gcprolist = 0;
1246: }
1247: 
1248: void
1249: syms_of_alloc ()
1250: {
1251:   DefIntVar ("gc-cons-threshold", &gc_cons_threshold,
1252:     "*Number of bytes of consing between garbage collections.");
1253: 
1254:   DefIntVar ("pure-bytes-used", &pureptr,
1255:     "Number of bytes of sharable Lisp data allocated so far.");
1256: 
1257:   DefIntVar ("data-bytes-used", &malloc_sbrk_used,
1258:     "Number of bytes of unshared memory allocated in this session.");
1259: 
1260:   DefIntVar ("data-bytes-free", &malloc_sbrk_unused,
1261:     "Number of bytes of unshared memory remaining available in this session.");
1262: 
1263:   DefLispVar ("purify-flag", &Vpurify_flag,
1264:     "Non-nil means defun should purecopy the function definition.");
1265: 
1266:   defsubr (&Scons);
1267:   defsubr (&Slist);
1268:   defsubr (&Svector);
1269:   defsubr (&Smake_list);
1270:   defsubr (&Smake_vector);
1271:   defsubr (&Smake_string);
1272:   defsubr (&Smake_symbol);
1273:   defsubr (&Smake_marker);
1274:   defsubr (&Spurecopy);
1275:   defsubr (&Sgarbage_collect);
1276: }

Defined functions

DEFUN defined in line 685; never used
clear_marks defined in line 792; used 3 times
free_cons defined in line 141; used 1 times
gc_sweep defined in line 1067; used 2 times
init_alloc defined in line 1243; used 1 times
init_alloc_once defined in line 1216; used 1 times
init_cons defined in line 130; used 1 times
init_marker defined in line 349; used 1 times
init_strings defined in line 422; used 2 times
init_symbol defined in line 286; used 1 times
make_pure_string defined in line 525; used 10 times
make_pure_vector defined in line 559; used 3 times
make_zero_string defined in line 463; used 3 times
malloc_warning defined in line 71; used 3 times
malloc_warning_1 defined in line 63; used 1 times
  • in line 76
mark_buffer defined in line 1025; used 1 times
mark_object defined in line 876; used 47 times
memory_full defined in line 80; used 11 times
pure_cons defined in line 544; used 3 times
syms_of_alloc defined in line 1248; used 1 times

Defined variables

Vpurify_flag defined in line 54; used 2 times
all_vectors defined in line 217; used 5 times
cons_block defined in line 125; used 9 times
cons_block_index defined in line 126; used 6 times
cons_free_list defined in line 128; used 10 times
consing_since_gc defined in line 30; used 9 times
current_string_block defined in line 420; used 15 times
dont_copy_flag defined in line 676; used 4 times
gc_cons_threshold defined in line 33; used 4 times
gc_in_progress defined in line 36; used 2 times
gcprolist defined in line 626; used 12 times
marker_block defined in line 344; used 9 times
marker_block_index defined in line 345; used 6 times
marker_free_list defined in line 347; used 8 times
most_negative_fixnum defined in line 671; used 8 times
pure defined in line 56; used 5 times
pureptr defined in line 61; used 11 times
staticidx defined in line 632; used 4 times
staticvec1 defined in line 630; used 1 times
symbol_block defined in line 281; used 9 times
symbol_block_index defined in line 282; used 6 times
symbol_free_list defined in line 284; used 8 times
total_conses defined in line 678; used 2 times
total_free_conses defined in line 679; used 2 times
total_free_markers defined in line 679; used 2 times
total_free_symbols defined in line 679; used 2 times
total_markers defined in line 678; used 2 times
total_string_size defined in line 678; used 3 times
total_symbols defined in line 678; used 2 times
total_vector_size defined in line 678; used 3 times

Defined struct's

backtrace defined in line 657; used 6 times
catchtag defined in line 647; used 6 times
cons_block defined in line 119; used 18 times
marker_block defined in line 338; used 18 times
string_block defined in line 410; used 33 times
string_block_head defined in line 404; used 6 times
symbol_block defined in line 275; used 18 times

Defined macros

CONS_BLOCK_SIZE defined in line 116; used 4 times
MARKER_BLOCK_SIZE defined in line 335; used 4 times
NSTATICS defined in line 628; used 2 times
PUREBEG defined in line 58; used 3 times
STRING_BLOCK_OUTSIZE defined in line 402; used 1 times
STRING_BLOCK_SIZE defined in line 398; used 2 times
SYMBOL_BLOCK_SIZE defined in line 272; used 4 times
staticvec defined in line 634; used 3 times
Last modified: 1986-03-27
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3254
Valid CSS Valid XHTML 1.0 Strict