home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / programming / gnusmalltalk / mstoop.c < prev    next >
C/C++ Source or Header  |  1992-06-11  |  42KB  |  1,612 lines

  1. /***********************************************************************
  2.  *
  3.  *    Object Table maintenance module.
  4.  *
  5.  ***********************************************************************/
  6.  
  7. /***********************************************************************
  8.  *
  9.  * Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
  10.  * Written by Steve Byrne.
  11.  *
  12.  * This file is part of GNU Smalltalk.
  13.  *
  14.  * GNU Smalltalk is free software; you can redistribute it and/or modify it
  15.  * under the terms of the GNU General Public License as published by the Free
  16.  * Software Foundation; either version 1, or (at your option) any later 
  17.  * version.
  18.  * 
  19.  * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
  20.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
  21.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  22.  * more details.
  23.  * 
  24.  * You should have received a copy of the GNU General Public License along with
  25.  * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
  26.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  
  27.  *
  28.  ***********************************************************************/
  29.  
  30.  
  31. /*
  32.  *    Change Log
  33.  * ============================================================================
  34.  * Author      Date       Change 
  35.  * sbb         31 Dec 91      Added registered oops to root set.
  36.  *
  37.  * sbb         31 Dec 91      oopTable now allocated from memory instead of being
  38.  *              stored as part of the executable.
  39.  *
  40.  * sbb          8 Dec 91      Changed oopValid to only check the FREE bit, instead
  41.  *              of worrying about the even odd flags, which may not
  42.  *              be valid.
  43.  *
  44.  * sbb         20 Oct 91      Support for growing now fully operational (and no, it
  45.  *              hasn't taken me over a month to track down the
  46.  *              problems; free time has been nil).  Also removed more
  47.  *              vestiges of the incremental GC.
  48.  *
  49.  * sbb         15 Sep 91      Added support for loading larger semispaces from
  50.  *              saved images.
  51.  *
  52.  * sbb          4 Aug 91      Removed more vestiges of the incremental GC, began
  53.  *              switchover to automatically growing semi-spaces.
  54.  *
  55.  * sbb         13 Oct 90      Converted to use bit masks instead of bit fields,
  56.  *              hoping to improve performance somewhat.
  57.  *
  58.  * sbyrne     8 Apr 90      Changed oopFree to oopValid to fix the bug with
  59.  *              someInstance losing after GC's due to objects that
  60.  *              have non-free OOP table entries, but point to freed
  61.  *              objects.
  62.  *
  63.  * sbyrne     7 Apr 90      Increased mem space size to 4M.  This can be
  64.  *              decreased as necessary.
  65.  *
  66.  * sbyrne    24 Feb 90      Update to change log: there are no longer any
  67.  *              explicitly allocated OOPs due to the new symbol table
  68.  *              structure; the comment below is now a noop.
  69.  *
  70.  * sbyrne    20 Sep 89      Added oop table slot GC'ing.  I'm not dealing with
  71.  *              oop table slots that are explictly allocated; I
  72.  *              believe that most OOP slots are not explicitly chosen
  73.  *              and so not running the incremental reclaimer for that
  74.  *              case shouldn't hurt us.
  75.  *
  76.  * sbyrne    12 Sep 89      Much of the garbage collector's operation depends on
  77.  *              the fact that only 1 flip will occur between any two
  78.  *              operations (such as a compilation, or a byte-code).
  79.  *              The code would be much more complex if this were not
  80.  *              the case, and I'm not sure that things would even be
  81.  *              possible if this were not the case.  Anyway, there is
  82.  *              code in this routine to check for that eventuality
  83.  *              and to halt the system if it occurs.
  84.  *
  85.  * sbyrne     6 Sep 89      started implementing the garbage collector (YAY!!!)
  86.  *
  87.  * sbyrne    13 Jan 89      Created.
  88.  *
  89.  */
  90.  
  91.  
  92. #include <stdio.h>
  93. #include "mst.h"
  94. #include "mstoop.h"
  95. #include "mstdict.h"
  96. #include "mstsave.h"
  97. #include "mstcomp.h"
  98. #include "mstcallin.h"
  99.  
  100. /* Size of the object semi spaces, in bytes */
  101. #define    K        1024
  102.  
  103. #ifndef atarist
  104. /* Min for Kernel = 512K, Kernel+STIX min is 1M */
  105. /* you can increase this value if you need more space, and it won't hurt
  106.  * performance *if* your machine has enough physical memory (otherwise, you
  107.  * thrash the pager) */
  108. #ifdef AMIGA
  109. #define INIT_MEM_SPACE_SIZE        /*(512 * K) */ (1500 * K)
  110. #else
  111. #define INIT_MEM_SPACE_SIZE        /*(512 * K) */ (2 * K * K)
  112. #endif
  113. #else
  114. #define INIT_MEM_SPACE_SIZE        (1152 * K) 
  115. #endif
  116.  
  117. #ifdef pre_full_gc /* Sun Aug  4 19:00:10 1991 */
  118. /**/#define oopReclaimFactor    4 /* how many oops to reclaim per oop alloc */
  119. #endif /* pre_full_gc Sun Aug  4 19:00:10 1991 */
  120.  
  121.  
  122. /* Define this flag to turn on debugging code for OOP table management */
  123. /* #define OOP_DEBUGGING */
  124.  
  125.  
  126.  
  127. #define alignSize(size) \
  128.  ( ((size) + DOUBLE_ALIGNMENT - 1) & ~(DOUBLE_ALIGNMENT - 1) )
  129.  
  130. #define objSpace(obj) \
  131.   ( (((char *)(obj) >= spaces[1].space) \
  132.      && ((char *)(obj) < spaces[1].space + spaces[1].totalSize)) \
  133.    ? F_SPACE : 0 )
  134.  
  135. /* Returns 1 if space flag represents the ODD space, 0 for the EVEN space */
  136. #define boolSpace(spaceFlag) \
  137.   ((spaceFlag) == F_SPACE)
  138.  
  139. #define EVEN_ODD_MASK (F_EVEN | F_ODD)
  140.  
  141. typedef struct CompiledMethodStruct *Method;
  142.  
  143. extern Boolean        regressionTesting;
  144.  
  145. /* These are the real OOPS for nil, true, and false */
  146. OOP            nilOOP, trueOOP, falseOOP;
  147.  
  148. /* The OOP table.  This contains a pointer to the object, and some flag
  149.    bits indicating which semispace the pointed-to object lives in.  Some
  150.    of the bits indicate the difference between the allocated length (stored 
  151.    in the object itself, and the real length, for things like byte strings 
  152.    that may not be an even multiple of 4 (== sizeof(void *)). */
  153. struct OOPStruct    *oopTable;
  154.  
  155. #ifdef pre_full_gc /* Sun Aug  4 19:00:44 1991 */
  156. /**//* This is the head of the free list.  The free list is maintained in the 
  157. /**/   oop table.  Each OOP on the free list has a bit indicating that it''s free,
  158. /**/   a pointer to the next free OOP, and a pointer to the previous free OOP.
  159. /**/   when this points at NIL, we''re out of space */
  160. /**/OOP            freeOOPs;
  161. #endif /* pre_full_gc Sun Aug  4 19:00:44 1991 */
  162. int            numFreeOOPs;
  163.  
  164. /* The indices of which is the current new space (toSpace) and which is
  165.    the current old space (fromSpace).  At GC flip time, these two are 
  166.    interchanged. */
  167. unsigned long        fromSpace, toSpace;
  168.  
  169. Boolean            gcFlipped, gcState, gcMessage;
  170. int            gcFlipCounter;
  171.  
  172. /* If there is this much space used after a gcFlip, we need to grow the other
  173.  * semi space by spaceGrowRate next time we gcFlip, so that the storage gets
  174.  * copied into the new, larger area.
  175.  */
  176. double            growThresholdPercent = 80.0;
  177.  
  178. /* Grow the semi spaces by this percentage when the amount of space used
  179.  * exceeds growThresholdPercent.
  180.  */
  181. double            spaceGrowRate = 30.0;
  182.  
  183. /* This vector holds the storage for all the Character objects in the system.
  184.    Since all character objects are unique, we pre-allocate space for 256 of
  185.    them, and treat them as special built-ins when doing garbage collection.*/
  186. CharObject        charObjectTable[NUM_CHAR_OBJECTS];
  187.  
  188. /* This is "nil" object in the system.  That is, the single instance of the
  189.    UndefinedObject class, which is called "nil". */
  190. struct NilObjectStruct    nilObject;
  191.  
  192. /* These represent the two boolean objects in the system, true and false.
  193.    This is the object storage for those two objects. 
  194.    false == &booleanObjects[0], true == &booleanObjects[1] */
  195. struct BooleanObjectStruct booleanObjects[2];
  196.  
  197. struct memorySpaceStruct {
  198.   char        *space;        /* base of allocated storage */
  199.   char        *allocPtr;    /* new space ptr, starts hi, goes down */
  200.   char        *copyPtr;    /* used by GC, points to highest copied space */
  201.   char        *scanPtr;    /* used by GC, points to highest scanned addr  */
  202.   unsigned long    size;        /* current remaining size */
  203.   unsigned long    totalSize;    /* current allocated size */
  204.   double    percentUsed;    /* amount used at just after copyReferences */
  205. };
  206.  
  207. /* This contains the maximum size of a semi space.  It is checked before a
  208.  * semi space gets used at gcflip time; if the space is too small, it is 
  209.  * brought up to spec before being used
  210.  */
  211. unsigned long    maxSpaceSize;
  212.  
  213. /* These two variables represent information about the semispaces.  spaces
  214.    holds the information for each semispace (basically the pointer to the
  215.    base of the space, and the pointers into it for allocation, copying, and
  216.    scanning.  curSpace holds the address of one of the two semispace data
  217.    structures, and is used by the garbage collector */
  218. static struct memorySpaceStruct spaces[2];
  219. static struct memorySpaceStruct *curSpace;
  220.  
  221. /* This contains the bit mask of the current toSpace: it's F_EVEN when
  222.    toSpace is 0, and F_ODD when toSpace is not zero */
  223. static unsigned long    evenOddFlag;
  224.  
  225. #ifdef pre_full_gc /* Sun Aug  4 19:22:24 1991 */
  226. /**/static Object        curObject;
  227. /**/static long        curObjectSize/* , copyQuota*/;
  228. #endif /* pre_full_gc Sun Aug  4 19:22:24 1991 */
  229. #ifdef preserved /* Sat Aug  3 18:47:58 1991 */
  230. /**/static double        copyRate;
  231. /**/static double        copyRateAdjustment = 1.50; /* copy 50% more than last time */
  232. #endif /* preserved Sat Aug  3 18:47:58 1991 */
  233. static long        oopTableIndex;
  234.  
  235. static Object        moveObject();
  236. static Boolean        isOOPAddr(), isObjAddr();
  237. static void        initCharObject(), moveRootOOPs(),
  238.             initSpace(), markBuiltinOOPs(), 
  239.             copyReferencedObjects(), clearOldOOPs(),
  240.             displayOOP(), displayObject();
  241.  
  242.  
  243. /*
  244.  *    void initOOPTable()
  245.  *
  246.  * Description
  247.  *
  248.  *    Initialize the OOP table.  Initially, all the OOPs are on the OOP free
  249.  *    list so that's just how we initialize them.  We do as much
  250.  *    initialization as we can, but we're called before classses are
  251.  *    defined, so things that have definite classes must wait until
  252.  *    the classes are defined.
  253.  *
  254.  */
  255. void initOOPTable()
  256. {
  257.   int        i;
  258.  
  259.   allocOOPTable();
  260.  
  261.   numFreeOOPs = OOP_TABLE_SIZE;
  262.  
  263.   for (i = 0; i < OOP_TABLE_SIZE; i++) {
  264.     /* forward chain free list of oops */
  265.     oopTable[i].flags = F_FREE;
  266. #ifdef pre_sc_gc /* Sat Jul 27 22:02:13 1991 */
  267. /**/    oopTable[i].object = (Object)&oopTable[i+1];
  268. /**/    oopTable[i].flags |= F_FREE;
  269. #endif /* pre_sc_gc Sat Jul 27 22:02:13 1991 */
  270.   }
  271. #ifdef pre_sc_gc /* Sat Jul 27 22:03:03 1991 */
  272. /**/  oopTable[i-1].object = nil;
  273. /**/
  274. /**/  freeOOPs = oopTable;
  275. #endif /* pre_sc_gc Sat Jul 27 22:03:03 1991 */
  276.  
  277.   nilOOP    = &oopTable[nilOOPIndex];
  278.   trueOOP    = &oopTable[trueOOPIndex];
  279.   falseOOP    = &oopTable[falseOOPIndex];
  280.  
  281.   nilOOP->flags        = trueOOP->flags        = falseOOP->flags    = 0;
  282.  
  283.   nilOOP->object    = (Object)&nilObject;
  284.   nilObject.objSize    = ROUNDED_WORDS(sizeof(struct NilObjectStruct));
  285.  
  286.   trueOOP->object        = (Object)&booleanObjects[0];
  287.   falseOOP->object        = (Object)&booleanObjects[1];
  288.   booleanObjects[0].objSize    = ROUNDED_WORDS(sizeof(struct BooleanObjectStruct));
  289.   booleanObjects[1].objSize    = ROUNDED_WORDS(sizeof(struct BooleanObjectStruct));
  290.   booleanObjects[0].booleanValue= trueOOP;
  291.   booleanObjects[1].booleanValue= falseOOP;
  292.  
  293. dictInit();            /* ### TEMP HACK ### */
  294.  
  295. }
  296.  
  297.  
  298. void allocOOPTable()
  299. {
  300.   oopTable = (struct OOPStruct *)malloc(sizeof(struct OOPStruct)
  301.                     *TOTAL_OOP_TABLE_SLOTS);
  302.   if (oopTable == NULL) {
  303.     errorf("Failed to allocate oopTable!!!");
  304.     exit(1);
  305.   }
  306. }
  307.  
  308.  
  309. /*
  310.  *    void initNil()
  311.  *
  312.  * Description
  313.  *
  314.  *    Initialize the "nil" object.
  315.  *
  316.  */
  317. void initNil()
  318. {
  319.   nilObject.objClass    = undefinedObjectClass;
  320. }
  321.  
  322. /*
  323.  *    void initBooleans()
  324.  *
  325.  * Description
  326.  *
  327.  *    Initialize the two boolean objects, after their respective classes have
  328.  *    been created.
  329.  *
  330.  */
  331. void initBooleans()
  332. {
  333.   booleanObjects[0].objClass    = trueClass;
  334.   booleanObjects[1].objClass    = falseClass;
  335. }
  336.  
  337. /*
  338.  *    void initCharTable()
  339.  *
  340.  * Description
  341.  *
  342.  *    Initialize the instances of the class Character, after that class has
  343.  *    been created.
  344.  *
  345.  */
  346. void initCharTable()
  347. {
  348.   int        i;
  349.  
  350.   for (i = 0; i < NUM_CHAR_OBJECTS; i++) {
  351.     initCharObject(i);
  352.     oopTable[i + CHAR_OBJECT_BASE].object = (Object)&charObjectTable[i];
  353.     oopTable[i + CHAR_OBJECT_BASE].flags = 0;
  354.   }
  355. }
  356.  
  357. /*
  358.  *    static void initCharObject(i)
  359.  *
  360.  * Description
  361.  *
  362.  *    Initialize a single character object.
  363.  *
  364.  * Inputs
  365.  *
  366.  *    i     : The index of the character object, in the range 0..255.
  367.  *
  368.  */
  369. static void initCharObject(i)
  370. int    i;
  371. {
  372.   charObjectTable[i].objSize = ROUNDED_WORDS(sizeof(CharObject));
  373.   charObjectTable[i].objClass = charClass;
  374.   charObjectTable[i].charVal = i;
  375. }
  376.  
  377. /*
  378.  *    void fixupMetaclassObjects()
  379.  *
  380.  * Description
  381.  *
  382.  *    Called after the fundamental class hierarchy has been defined, this
  383.  *    function goes through and fixes up all the objects in the oop table
  384.  *    that don't have a objClass (objClass == nilOOP).  It's a
  385.  *    chicken-and-egg problem: the metaclassClass doesn't yet exist when the
  386.  *    hierarchy is put together, so after it's created, we have to go back
  387.  *    and fix all the metaclasses that we created.
  388.  *
  389.  */
  390. void fixupMetaclassObjects()
  391. {
  392.   int        i;
  393.  
  394.   for (i = 0; i < OOP_TABLE_SIZE; i++) {
  395.     if (!(oopTable[i].flags & F_FREE) && isNil(oopTable[i].object->objClass)) {
  396.       oopTable[i].object->objClass = metaclassClass;
  397.     }
  398.   }
  399. }
  400.  
  401. /*
  402.  *    OOP findAnInstance(classOOP)
  403.  *
  404.  * Description
  405.  *
  406.  *    Finds and returns an instance of the class CLASSOOP.  Returns "nil" if
  407.  *    there are no instances present.
  408.  *
  409.  * Inputs
  410.  *
  411.  *    classOOP: 
  412.  *        OOP for a class for which to find an instance
  413.  *
  414.  * Outputs
  415.  *
  416.  *    The first instance of the given class in the OOP table.
  417.  */
  418. OOP findAnInstance(classOOP)
  419. OOP    classOOP;
  420. {
  421.   register OOP    oop;
  422.  
  423.   for (oop = oopTable; oop < &oopTable[OOP_TABLE_SIZE]; oop++) {
  424.     if (!(oop->flags & F_FREE)
  425.     && oop->object->objClass == classOOP) {
  426.       return (oop);
  427.     }
  428.   }
  429.  
  430.   return (nilOOP);
  431. }
  432.  
  433. #ifndef INLINE_MACROS
  434. /*
  435.  *    long oopIndex(oop)
  436.  *
  437.  * Description
  438.  *
  439.  *    Returns the index within the OOP table of the given OOP.
  440.  *
  441.  * Inputs
  442.  *
  443.  *    oop   : OOP to return index of
  444.  *
  445.  * Outputs
  446.  *
  447.  *    Returned index in the OOP table, in range 0..TOTAL_OOP_TABLE_SLOTS.
  448.  */
  449. long oopIndex(oop)
  450. OOP    oop;
  451. {
  452.   return (oopIndexMac(oop));
  453. }
  454. #endif /* INLINE_MACROS */
  455.  
  456. /*
  457.  *    Boolean oopIndexValid(index)
  458.  *
  459.  * Description
  460.  *
  461.  *    Checks to see if index represents a valid OOP.
  462.  *
  463.  * Inputs
  464.  *
  465.  *    index : a long index into the OOP table, apparently 1 based due to
  466.  *        being called from Smalltalk via a primitive.
  467.  *
  468.  * Outputs
  469.  *
  470.  *    True if the index represents a valid OOP table element, false
  471.  *    otherwise.
  472.  */
  473. Boolean oopIndexValid(index)
  474. long    index;
  475. {
  476.   return (index >= 1 && index <= TOTAL_OOP_TABLE_SLOTS);
  477. }
  478.  
  479. #ifndef INLINE_MACROS
  480.  
  481. OOP oopAt(index)
  482. long    index;
  483. {
  484.   return (oopAtMac(index));
  485. }
  486.  
  487. void prepareToStore(destOOP, srcOOP)
  488. OOP    destOOP, srcOOP;
  489. {
  490.   prepareToStoreMac(destOOP, srcOOP);
  491. }
  492.  
  493. #endif  /* INLINE_MACROS */
  494.  
  495. void swapObjects(oop1, oop2)
  496. OOP    oop1, oop2;
  497. {
  498.   struct OOPStruct tempOOP;
  499.  
  500.   tempOOP = *oop2;
  501.   *oop2 = *oop1;
  502.   *oop1 = tempOOP;
  503. }
  504.  
  505. OOP charOOPAt(c)
  506. Byte    c;
  507. {
  508.   return (&oopTable[c + CHAR_OBJECT_BASE]);
  509. }
  510.  
  511. Byte charOOPValue(charOOP)
  512. OOP    charOOP;
  513. {
  514.   return (charOOP - &oopTable[CHAR_OBJECT_BASE]);
  515. }
  516.  
  517. void printObject(oop)
  518. OOP    oop;
  519. {
  520.   if (isInt(oop)) {
  521.     printf("%d", toInt(oop));
  522.   } else if (isNil(oop)) {
  523.     printf("nil");
  524.   } else if (oop == trueOOP) {
  525.     printf("true");
  526.   } else if (oop == falseOOP) {
  527.     printf("false");
  528.   } else if (oopClass(oop) == charClass) {
  529.     printf("$%c", charOOPValue(oop));
  530.   } else if (oopClass(oop) == floatClass) {
  531.     printf("%#g", floatOOPValue(oop));
  532.   } else if (oopClass(oop) == symbolClass) {
  533.     printf("#"); printSymbol(oop);
  534.   } else if (oopClass(oop) == stringClass) {
  535.     /* ### have to quote embedded quote chars */
  536.     printf("'");
  537.     printString(oop);
  538.     printf("'");
  539.   } else {
  540.     printOOPConstructor(oop);
  541.   }
  542. }
  543.  
  544. void classifyAddr(addr)
  545. void    *addr;
  546. {
  547.   if (isOOPAddr(addr)) {
  548.     displayOOP(addr);
  549.   } else if (isObjAddr(addr)) {
  550.     displayObject(addr);
  551.   } else if isInt(addr) {
  552.     printf("Smalltalk Integer %d\n", toInt(addr));
  553.   } else {
  554.     printf("Address %#x is not a Smalltalk entity\n", addr);
  555.   }
  556. }
  557.  
  558. static Boolean isOOPAddr(addr)
  559. OOP    addr;
  560. {
  561.   if (addr >= oopTable && addr < &oopTable[TOTAL_OOP_TABLE_SLOTS]) {
  562.     if ((long)addr % 4 == 0) {
  563.       return (true);
  564.     }
  565.   }
  566.  
  567.   return (false);
  568. }
  569.  
  570.  
  571. static Boolean isObjAddr(addr)
  572. char    *addr;
  573. {
  574.   if ((addr >= spaces[0].space && addr < spaces[0].space + spaces[0].totalSize)
  575.       || (addr >= spaces[1].space && addr < spaces[1].space + spaces[1].totalSize)) {
  576.     if ((long)addr % 4 == 0) {
  577.       return (true);
  578.     }
  579.   }
  580.  
  581.   return (false);
  582. }
  583.   
  584. static void displayOOP(oop)
  585. OOP    oop;
  586. {
  587.   Boolean    isBuiltin;
  588.   
  589.   if (!isOOPAddr(oop)) {
  590.     printf("Parameter %#x does not appear to be an OOP!\n", oop);
  591.     return;
  592.   }
  593.  
  594.   isBuiltin = (oop >= &oopTable[OOP_TABLE_SIZE]) ? true : false;
  595.  
  596.   if (!isBuiltin) {
  597.     printf ("OOP %#x [%d]\n", oop, oop - oopTable);
  598.   }
  599.  
  600.   if (oop->flags & F_FREE) {
  601.     printf("Free ");
  602.   }
  603.   printf("Space=%d ", (oop->flags & F_SPACE) ? 1 : 0);
  604.   if (oop->flags & F_EVEN) {
  605.     printf("Even ");
  606.   }
  607.   if (oop->flags & F_ODD) {
  608.     printf("Odd ");
  609.   }
  610.   if (oop->flags & F_FAKE) {
  611.     printf("Fake ");
  612.   }
  613.  
  614.   printf("   Empty bytes = %d\n", oop->flags & EMPTY_BYTES);
  615.   if (!(oop->flags & F_FREE)) {
  616.     printObject(oop);
  617.   }
  618.   printf("\n");
  619. }
  620.  
  621.  
  622. static void displayObject(obj)
  623. Object    obj;
  624. {
  625.   int        space;
  626.  
  627.   if (!isObjAddr(obj)) {
  628.     printf("Parameter %#x does not appear to be an object!\n", obj);
  629.     return;
  630.   }
  631.     
  632.   space = objSpace(obj) != 0;
  633.   printf("Object at %#x, in space %d (curSpace is %d), ", obj, space,
  634.      curSpace == &spaces[1]);
  635.   if ((char *)obj >= spaces[space].allocPtr) {
  636.     printf("allocated this GC pass\n");
  637.   } else if ((char *)obj >= spaces[space].scanPtr) {
  638.     printf("copied in this GC pass, not scanned\n");
  639.   } else {
  640.     printf("copied in this GC pass, scanned\n");
  641.   }
  642.   
  643.   printf("Size %d\n", numOOPs(obj));
  644.   printf("Class ");
  645.   printObject(obj->objClass);
  646.   printf("\n");
  647. }
  648.  
  649.  
  650. Boolean oopValid(oop)
  651. OOP    oop;
  652. {
  653.   /* In the non-incremental GC world, being FREE is all that matters for
  654.    * validity.
  655.    */
  656.   return (!(oop->flags & F_FREE));
  657. #ifdef old_code /* Sun Dec  8 16:01:28 1991 */
  658. /**/  return (!(oop->flags & F_FREE) && (oop->flags & (F_EVEN|F_ODD)) );
  659. #endif /* old_code Sun Dec  8 16:01:28 1991 */
  660. }
  661.  
  662. #ifndef INLINE_MACROS
  663.  
  664. Boolean oopAvailable(index)
  665. long    index;
  666. {
  667.   return (oopAvailableMac(index));
  668. }
  669.  
  670. #endif /* INLINE_MACROS */
  671.  
  672. /*
  673.  *    OOP allocOOP(obj)
  674.  *
  675.  * Description
  676.  *
  677.  *    Given an object OBJ, this routine allocates an OOP table slot for it
  678.  *    and returns it.  It marks the OOP so that it indicates the object is in
  679.  *    new space, and that the oop has been referenced on this pass (to keep
  680.  *    the OOP table reaper from reclaiming this OOP).
  681.  *
  682.  * Inputs
  683.  *
  684.  *    obj   : Object that the new OOP should point to.
  685.  *
  686.  * Outputs
  687.  *
  688.  *    An OOP, which is the address of an element in the OOP table.
  689.  */
  690. OOP allocOOP(obj)
  691. Object    obj;
  692. {
  693.   register OOP        oop;
  694.  
  695.   for (oop = &oopTable[oopTableIndex];
  696.        oop < &oopTable[OOP_TABLE_SIZE]; oop++) {
  697.     if (oop->flags & F_FREE) {
  698.       oopTableIndex = oop - oopTable + 1;
  699.  
  700.       numFreeOOPs--;
  701.       /* !!! not sure if this is needed */
  702.       if (objSpace(obj) != toSpace) {
  703. /* dprintf("doing move for oldspace object in allocOOP\n"); */
  704.     obj = moveObject(obj);
  705.       }
  706.       oop->object = obj;
  707.       oop->flags = toSpace | evenOddFlag;
  708.       return (oop);
  709.     }
  710.   }
  711.  
  712.   errorf("Ran out of OOP Table slots!!!");
  713.   exit(1);
  714. }
  715.  
  716. #ifdef preserved /* Sat Jul 27 16:48:12 1991 */
  717. /**/OOP allocOOP(obj)
  718. /**/Object    obj;
  719. /**/{
  720. /**/#ifndef NORMAL_ALLOC_OOP
  721. /**/  register OOP        oop;
  722. /**/  register int        i;
  723. /**/
  724. /**/  for (i = 0, oop = &oopTable[oopTableIndex];
  725. /**/       i < oopReclaimFactor && oop < &oopTable[OOP_TABLE_SIZE]; i++, oop++) {
  726. /**/    if (!(oop->flags & F_FREE)) {
  727. /**/      if (!(oop->flags & (F_EVEN|F_ODD))) {
  728. /**/    /* we've found a dead one...add it to the free list */
  729. /**/    numFreeOOPs++;
  730. /**/    oop->object = (Object)freeOOPs;
  731. /**/    freeOOPs = oop;
  732. /**/    freeOOPs->flags |= F_FREE;
  733. /**/      } else {
  734. /**/    /* turn off the bit for the space we're not in */
  735. /**/    oop->flags &= ~(evenOddFlag ^ EVEN_ODD_MASK);
  736. /**/      }
  737. /**/    }
  738. /**/  }
  739. /**/
  740. /**/  oopTableIndex = oop - oopTable;
  741. /**/
  742. /**/#else
  743. /**/  OOP        oop;
  744. /**/  register int        i;
  745. /**/
  746. /**/  for (i = 0; i < oopReclaimFactor; i++) {
  747. /**/    if (oopTableIndex >= OOP_TABLE_SIZE) {
  748. /**/      break;
  749. /**/    }
  750. /**/    oop = &oopTable[oopTableIndex++];
  751. /**/    if (!oop->isFree) {
  752. /**/      if (!oop->evenMark && !oop->oddMark) {
  753. /**/    /* we've found a dead one...add it to the free list */
  754. /**/    numFreeOOPs++;
  755. /**/    oop->object = (Object)freeOOPs;
  756. /**/    freeOOPs = oop;
  757. /**/    freeOOPs->isFree = true;
  758. /**/      } else if (toSpace) {
  759. /**/    oop->evenMark = 0;
  760. /**/      } else {
  761. /**/    oop->oddMark = 0;
  762. /**/      }
  763. /**/    }
  764. /**/  }
  765. /**/#endif
  766. /**/
  767. /**/  oop = freeOOPs;
  768. /**/
  769. /**/  numFreeOOPs--;
  770. /**/
  771. /**/  if (oop == nil) {
  772. /**/    errorf("Ran out of OOP Table slots!!!");
  773. /**/    exit(1);
  774. /**/    /* ### this needs to be fixed */
  775. /**/  }
  776. /**/
  777. /**/  if (!(oop->flags & F_FREE)) {
  778. /**/    errorf("Allocating allocated OOP!!!");
  779. /**/    exit(0);
  780. /**/  }
  781. /**/
  782. /**/  freeOOPs = (OOP)oop->object;
  783. /**/
  784. /**/  if (objSpace(obj) != toSpace) {
  785. /**/    obj = moveObject(obj);
  786. /**/  }
  787. /**/
  788. /**/
  789. /**/  oop->object = obj;
  790. /**/  oop->flags = toSpace | evenOddFlag;
  791. /**/
  792. /**/  return (oop);
  793. /**/}
  794. #endif /* preserved Sat Jul 27 16:48:12 1991 */
  795.  
  796.  
  797. /*
  798.  *    void setOOPObject(oop, object)
  799.  *
  800.  * Description
  801.  *
  802.  *    Sets the object of OOP to be OBJECT.  Makes sure that the object is in
  803.  *    new space before it assigns it to OOP.
  804.  *
  805.  * Inputs
  806.  *
  807.  *    oop   : an OOP table entry to be assigned into
  808.  *    object: an object that the OOP should point to.
  809.  *
  810.  */
  811. void setOOPObject(oop, object)
  812. OOP    oop;
  813. Object    object;
  814. {
  815. #ifndef OPTIMIZE
  816.   if (isFake(oop)) {
  817.     printf("found a fake oop %x\n", oop);
  818.     debug();
  819.   }
  820. #endif /* !OPTIMIZE */
  821.  
  822.   if (objSpace(object) != toSpace) {
  823. /* dprintf("doing move for oldspace object in setOOPObject\n"); */
  824.     object = moveObject(object);
  825.   }
  826.   oop->object = object;
  827.   oop->flags = (oop->flags & ~F_SPACE) | toSpace;
  828. }
  829.  
  830. /*
  831.  *    void initMem()
  832.  *
  833.  * Description
  834.  *
  835.  *    Initialize the memory allocator.  Both semispaces are allocated, and
  836.  *    the various garbage collection flags are set to their initial values.
  837.  *
  838.  */
  839. void initMem()
  840. {
  841.   int        i;
  842.  
  843.   maxSpaceSize = INIT_MEM_SPACE_SIZE;
  844.  
  845.   for (i = 0; i < 2; i++) {
  846.     spaces[i].space = (char *)malloc(maxSpaceSize);
  847.     spaces[i].totalSize = maxSpaceSize;
  848.     spaces[i].percentUsed = 0.0;
  849.     if (spaces[i].space == NULL) {
  850.       printf("Malloc failure; you're out of paging/swapping space\n");
  851.       exit(1);
  852.     }
  853.     initSpace(&spaces[i]);
  854.   }
  855.  
  856.   curSpace = &spaces[0];
  857.   toSpace = 0;
  858. #ifdef bogus_old_code /* Sat Oct 13 15:37:50 1990 */
  859. /**/  fromSpace = !toSpace;
  860. #endif /* bogus_old_code Sat Oct 13 15:37:50 1990 */
  861.   fromSpace = F_SPACE;
  862.   evenOddFlag = F_EVEN;
  863.   gcFlipped = false;
  864.   gcState = false;
  865.   gcMessage = true;
  866. #ifdef preserved /* Sat Aug  3 18:48:45 1991 */
  867. /**/  copyRate = 0.0;        /* don't copy anything until first flip */
  868. /**/  copyQuota = 0;
  869. #endif /* preserved Sat Aug  3 18:48:45 1991 */
  870.   oopTableIndex = 0;
  871. #ifdef testing_out /* Sat Feb 29 10:55:51 1992 */
  872. /**/  markBuiltinOOPs();
  873. #endif /* testing_out Sat Feb 29 10:55:51 1992 */
  874.   clearGCFlipFlags();
  875. }
  876.  
  877. Object curSpaceAddr()
  878. {
  879.   return ((Object)curSpace->space);
  880. }
  881.  
  882. void setSpaceInfo(size)
  883. long    size;
  884. {
  885.   curSpace->copyPtr = curSpace->scanPtr = curSpace->space + size;
  886.   curSpace->size -= size;
  887. }
  888.  
  889. #ifndef INLINE_MACROS
  890.  
  891. void clearGCFlipFlags()
  892. {
  893.   clearGCFlipFlagsMac();
  894. }
  895.  
  896. #endif /* INLINE_MACROS */
  897.  
  898. /*
  899.  *    Object allocObj(size)
  900.  *
  901.  * Description
  902.  *
  903.  *    Allocate and return space for an object of SIZE bytes.  This basically
  904.  *    means moving the allocation pointer for the current space down by SIZE
  905.  *    bytes, and, if there isn't enough space left, flipping the garbage
  906.  *    collector to switch semispaces.  The space is merely allocated; it is
  907.  *    not initialized.
  908.  *
  909.  * Inputs
  910.  *
  911.  *    size  : size in bytes of the object to allocate.  This will be rounded
  912.  *        by this routine up to a suitable boundary, typically to a 4
  913.  *        byte boundary.
  914.  *
  915.  * Outputs
  916.  *
  917.  *    Address of the newly allocated object.
  918.  */
  919. Object allocObj(size)
  920. long    size;
  921. {
  922.   size = alignSize(size);
  923.  
  924. #ifdef preserved /* Sat Jul 27 16:43:00 1991 */
  925. /**/  copyReferencedObjects((long)(size * copyRate));
  926. #endif /* preserved Sat Jul 27 16:43:00 1991 */
  927.   curSpace->allocPtr -= size;
  928.   while (curSpace->allocPtr <= curSpace->copyPtr) {
  929.     gcFlip();
  930.     curSpace->allocPtr -= size;
  931.   }
  932.  
  933. #ifdef preserved /* Fri Oct 18 21:46:22 1991 */
  934. /**/  if (curSpace->allocPtr <= curSpace->copyPtr) {
  935. /**/    gcFlip();
  936. /**/    curSpace->allocPtr -= size;
  937. /**/  }
  938. #endif /* preserved Fri Oct 18 21:46:22 1991 */
  939.     
  940.   return ((Object)curSpace->allocPtr);
  941. }
  942.  
  943.  
  944. /*
  945.  *    static void copyReferencedObjects()
  946.  *
  947.  * Description
  948.  *
  949.  *    This is the heart of the garbage collector.  It fully scans all objects
  950.  *    in new space, copying object that it finds that are still in old space
  951.  *    to new space and adding them to the set of objects to be scanned.
  952.  *    It has to special case
  953.  *    CompiledMethod objects due to their unusual structure.
  954.  *    
  955.  */
  956. static void copyReferencedObjects()
  957. {
  958.   Object    object;
  959.   register OOP    curClass, *oop;
  960.   int        stepSize, count;
  961.   Method    method;
  962.   register int    i;
  963.  
  964.   while (curSpace->scanPtr < curSpace->copyPtr) { /* there's more to scan */
  965.     /* if there is no current object, start off with the object's class */
  966.     object = (Object)curSpace->scanPtr;
  967.     curClass = object->objClass;
  968.       
  969. #ifdef debugging /* Mon Oct 28 12:29:31 1991 */
  970. /**/  if (curClass == stringClass) {
  971. /**/    fwrite(object->data, sizeof(Byte), numOOPs(object) * sizeof(OOP), stdout);
  972. /**/    fflush(stdout);
  973. /**/    printf("\n----------------------------------------\n");
  974. /**/  }
  975. #endif /* debugging Mon Oct 28 12:29:31 1991 */
  976.  
  977.  
  978. /*    { extern Boolean gcDebug;
  979.       if (gcDebug) {
  980.      dprintf("copying at %#8x, size %d\n", curSpace->scanPtr, object->objSize);
  981.       }
  982.     }
  983. */
  984.  
  985.     /* don't need to do the isInt test for this case */
  986.     localMaybeMoveOOP(curClass);
  987.       
  988.     stepSize = object->objSize * sizeof(OOP);
  989.     if (curClass == compiledMethodClass) {
  990.       /* Compiled methods have to be dealt with specially since they
  991.        * have a structure that's unlike a regular Smalltalk object:
  992.        * it has two fixed instance variables (description and 
  993.        * methodHeader), a variable number of literals, and then
  994.        * a bunch of bytecodes, which must be skipped over */
  995.       method = (Method)object;
  996.       localMaybeMoveOOP(method->descriptor);
  997.       if (method->header.headerFlag == 0 || method->header.headerFlag == 3) {
  998.     count = method->header.numLiterals;
  999.     for (i = 0; i < count; i++) {
  1000.       localMaybeMoveOOP(method->literals[i]);
  1001.     }
  1002.       }
  1003.  
  1004.     } else if (!classIsPointers(curClass)) {
  1005.       /* nothing to scan, just skip over it */
  1006.     } else {
  1007.       /* we've got an object with sub structure, so we set the object
  1008.        * size pointer to 2 words less than the object size (ignore
  1009.        * the header; we've already copied the class) and set the
  1010.        * scan pointer to the first word of the object.  We then continue
  1011.        * to go through the normal scanning procedure (fall out the
  1012.        * bottom of the if and go back to the top of the loop again)
  1013.        */
  1014.       count = numOOPs(object);
  1015.       for (i = 0, oop = object->data; i < count; i++, oop++) {
  1016.     localMaybeMoveOOP(*oop);
  1017.       }
  1018.       
  1019.     }
  1020.     curSpace->scanPtr += stepSize;
  1021.   }
  1022. }
  1023.  
  1024. #ifdef preserved /* Sat Jul 27 17:06:09 1991 */
  1025. /**/static void copyReferencedObjects(numBytes)
  1026. /**/long    numBytes;
  1027. /**/{
  1028. /**/  Object    object;
  1029. /**/  OOP        curClass;
  1030. /**/  int        stepSize, i;
  1031. /**/  Method    method;
  1032. /**/
  1033. /**/  copyQuota += numBytes;
  1034. /**/  while (curSpace->scanPtr < curSpace->copyPtr
  1035. /**/     && copyQuota > 0) { /* there's more to scan */
  1036. /**/    if (curObject == nil) {
  1037. /**/      /* if there is no current object, start off with the object's class */
  1038. /**/      object = (Object)curSpace->scanPtr;
  1039. /**/      curClass = object->objClass;
  1040. /**/      maybeMoveOOP(curClass);
  1041. /**/      
  1042. /**/      if (curClass == compiledMethodClass) {
  1043. /**/    /* Compiled methods have to be dealt with specially since they
  1044. /**/     * have a structure that''s unlike a regular Smalltalk object:
  1045. /**/     * it has two fixed instance variables (description and 
  1046. /**/     * methodHeader), a variable number of literals, and then
  1047. /**/     * a bunch of bytecodes, which must be skipped over */
  1048. /**/    stepSize = object->objSize * sizeof(OOP);
  1049. /**/    method = (Method)object;
  1050. /**/    maybeMoveOOP(method->descriptor);
  1051. /**/    if (method->header.headerFlag == 0 || method->header.headerFlag == 3) {
  1052. /**/      for (i = 0; i < method->header.numLiterals; i++) {
  1053. /**/        maybeMoveOOP(method->literals[i]);
  1054. /**/      }
  1055. /**/    }
  1056. /**/
  1057. /**/    curSpace->scanPtr += stepSize;
  1058. /**/    copyQuota -= stepSize;
  1059. /**/      } else if (!classIsPointers(curClass)) {
  1060. /**/    /* nothing to scan, just skip over it */
  1061. /**/    stepSize = object->objSize * sizeof(OOP);
  1062. /**/    curSpace->scanPtr += stepSize;
  1063. /**/    copyQuota -= stepSize;
  1064. /**/      } else {
  1065. /**/    /* we've got an object with sub structure, so we set the object
  1066. /**/     * size pointer to 2 words less than the object size (ignore
  1067. /**/     * the header; we''ve already copied the class) and set the
  1068. /**/     * scan pointer to the first word of the object.  We then continue
  1069. /**/     * to go through the normal scanning procedure (fall out the
  1070. /**/     * bottom of the if and go back to the top of the loop again)
  1071. /**/     */
  1072. /**/    curObject = object;
  1073. /**/    curObjectSize = numOOPs(curObject) * sizeof(OOP);
  1074. /**/    curSpace->scanPtr = (char *)curObject->data;
  1075. /**/      }
  1076. /**/
  1077. /**/    } else {
  1078. /**/      /* we're part way through scanning an object, continue to scan... */
  1079. /**/      if (curObjectSize <= 0) {
  1080. /**/    curObject = nil;
  1081. /**/      } else {
  1082. /**/    maybeMoveOOP(*(OOP *)curSpace->scanPtr);
  1083. /**/    stepSize = sizeof(OOP);
  1084. /**/    curSpace->scanPtr += stepSize;
  1085. /**/    curObjectSize -= stepSize;
  1086. /**/    copyQuota -= stepSize;
  1087. /**/      }
  1088. /**/    }
  1089. /**/  }
  1090. /**/
  1091. /**/  if (copyQuota < 0) {
  1092. /**/    copyQuota = 0;
  1093. /**/  }
  1094. /**/}
  1095. /**/
  1096. #endif /* preserved Sat Jul 27 17:06:09 1991 */
  1097. /*
  1098.  *    Boolean gcOff()
  1099.  *
  1100.  * Description
  1101.  *
  1102.  *    Turns off the garbage collector.  Returns the previous on/off state.
  1103.  *
  1104.  * Outputs
  1105.  *
  1106.  *    Previous state of the garbage collector (on or off).
  1107.  */
  1108. Boolean gcOff()
  1109. {
  1110.   Boolean    oldGCState;
  1111.  
  1112.   oldGCState = gcState;
  1113.   gcState = false;
  1114.   return (oldGCState);
  1115. }
  1116.  
  1117. /*
  1118.  *    void gcOn()
  1119.  *
  1120.  * Description
  1121.  *
  1122.  *    Turns on the garbage collector.
  1123.  *
  1124.  */
  1125. void gcOn()
  1126. {
  1127.   gcState = true;
  1128. }
  1129.  
  1130. /*
  1131.  *    void setGCState(state)
  1132.  *
  1133.  * Description
  1134.  *
  1135.  *    Set the garbage collector flag to the specified state (either on or
  1136.  *    off).
  1137.  *
  1138.  * Inputs
  1139.  *
  1140.  *    state : Boolean, true => gc on.
  1141.  *
  1142.  */
  1143. void setGCState(state)
  1144. Boolean    state;
  1145. {
  1146.   gcState = state;
  1147. }
  1148.  
  1149.  
  1150. /*
  1151.  *    static void clearOldOOPs()
  1152.  *
  1153.  * Description
  1154.  *
  1155.  *    Scans through the OOP table, removing OOPS that have died.  Only
  1156.  *    called at the end of a full GC to remove any stragglers.
  1157.  *
  1158.  */
  1159. static void clearOldOOPs()
  1160. {
  1161.   register OOP    oop;
  1162.  
  1163.   for (oop = oopTable; oop<&oopTable[OOP_TABLE_SIZE]; oop++) {
  1164.     if (!(oop->flags & F_FREE)) {
  1165.       if (!(oop->flags & evenOddFlag)) {
  1166.     /* we've found a dead one...add it to the free list */
  1167.     numFreeOOPs++;
  1168.     oop->flags = F_FREE;
  1169.       } else {
  1170.      /* !!! may not want to clear completey to 0? */
  1171.     oop->flags &= ~EVEN_ODD_MASK;
  1172.       }
  1173.     }
  1174.   
  1175. #ifdef pre_sc_gc /* Sat Jul 27 17:33:01 1991 */
  1176. /**/  for (oop = &oopTable[oopTableIndex]; oop<&oopTable[OOP_TABLE_SIZE]; oop++) {
  1177. /**/    if (!(oop->flags & F_FREE)) {
  1178. /**/      if (!(oop->flags & evenOddFlag)) {
  1179. /**/    /* we've found a dead one...add it to the free list */
  1180. /**/    numFreeOOPs++;
  1181. /**/    oop->object = (Object)freeOOPs;
  1182. /**/    freeOOPs = oop;
  1183. /**/    freeOOPs->flags |= F_FREE;
  1184. /**/      } else {
  1185. /**/    /* turn off the bit for the space we're not in  */
  1186. /**/    oop->flags &= ~(evenOddFlag ^ EVEN_ODD_MASK);
  1187. /**/      }
  1188. /**/    }
  1189. /**/  
  1190. #endif /* pre_sc_gc Sat Jul 27 17:33:01 1991 */
  1191.   }
  1192. }
  1193.  
  1194. /*
  1195.  *    void gcFlip()
  1196.  *
  1197.  * Description
  1198.  *
  1199.  *    Switches the garbage collector's notion of which space is "new" space
  1200.  *    and which is "old" space.  Readjusts the garbage collection parameters
  1201.  *    based on things like the allocation to copying ratio.  Copies the root
  1202.  *    set to new space.
  1203.  *
  1204.  */
  1205. void gcFlip()
  1206. {
  1207.   long        oldCopySize, oldNewSize;
  1208.   double    lastPercent;
  1209.  
  1210.   if (!gcState) {
  1211.     errorf("Attempted to do a gcFlip with garbage collector off!");
  1212.     exit(1);
  1213.   }
  1214.  
  1215. #ifndef OPTIMIZE
  1216.   if (gcFlipCounter >= 1) {
  1217.     errorf("Attempted to do a gcFlip too soon after a gcFlip!");
  1218.     exit(1);
  1219.   }
  1220. #endif
  1221.  
  1222.  
  1223. #ifdef OOP_DEBUGGING
  1224.   printf("%d free oops = %.2f%%, scanner was at %d/%d\n", numFreeOOPs,
  1225.        100.0 * numFreeOOPs / OOP_TABLE_SIZE, oopTableIndex, OOP_TABLE_SIZE);
  1226. #endif
  1227.  
  1228.   if (gcMessage && !regressionTesting) {
  1229.     /* print the first part of this message before we finish scanning 
  1230.      * oop table for live ones, so that the delay caused by this scanning
  1231.      * is apparent.
  1232.      */
  1233.     printf("\"GC flipping "); fflush(stdout);
  1234.   }
  1235.  
  1236.   oldCopySize = curSpace->copyPtr - curSpace->space;
  1237.   oldNewSize = curSpace->space + curSpace->totalSize - curSpace->allocPtr;
  1238.  
  1239. if (oldCopySize == 0) {  /* ### Experimental */
  1240.   oldCopySize = oldNewSize;
  1241. }
  1242.  
  1243.   lastPercent = curSpace->percentUsed;
  1244.  
  1245. #ifdef preserved /* Sat Jul 27 17:30:33 1991 */
  1246. /**/  copyRate = ((double)oldCopySize) / oldNewSize;
  1247. /**/  copyRate *= copyRateAdjustment;
  1248. #endif /* preserved Sat Jul 27 17:30:33 1991 */
  1249.  
  1250.   toSpace ^= F_SPACE;
  1251.   fromSpace ^= F_SPACE;
  1252.   evenOddFlag ^= EVEN_ODD_MASK;    /* switch which bit is in use */
  1253.   curSpace = &spaces[boolSpace(toSpace)];
  1254. #ifdef pre_full_gc /* Sun Aug  4 19:24:21 1991 */
  1255. /**/  curObject = nil;
  1256. #endif /* pre_full_gc Sun Aug  4 19:24:21 1991 */
  1257. #ifdef preserved /* Sat Aug  3 18:49:00 1991 */
  1258. /**/  copyQuota = 0;
  1259. #endif /* preserved Sat Aug  3 18:49:00 1991 */
  1260.   oopTableIndex = 0;
  1261.  
  1262.   if (lastPercent > growThresholdPercent) {
  1263.     maxSpaceSize *= 1.0 + spaceGrowRate/100.0;
  1264.     maxSpaceSize &= ~3;        /* round to word boundary */
  1265.   }
  1266.   
  1267.   initSpace(curSpace);
  1268.  
  1269.   moveRootOOPs();
  1270.   copyReferencedObjects(); /* copy what we can */
  1271.   clearOldOOPs();
  1272.  
  1273.   curSpace->percentUsed = (curSpace->scanPtr - curSpace->space) * 100.0
  1274.     / curSpace->totalSize; 
  1275.  
  1276.   /* if oldCopySize / size of space > threshold
  1277.         allocate new old space
  1278.      */
  1279.  
  1280.   /* note the use of quotation marks around the printed message.  The
  1281.      idea here was to make them appear as Smalltalk comments, so that 
  1282.      generated output could be fed to another Smalltalk without harm. */
  1283.   if (gcMessage && !regressionTesting) {
  1284.     printf("to space %d...", boolSpace(toSpace)); fflush(stdout);
  1285.     printf("copied space = %.1f%%...", curSpace->percentUsed);
  1286. #ifdef pre_full_gc /* Sun Aug  4 20:09:15 1991 */
  1287. /**/    printf("copied space = %.1f%%...", oldCopySize * 100.0 / MEM_SPACE_SIZE);
  1288. #endif /* pre_full_gc Sun Aug  4 20:09:15 1991 */
  1289.   }
  1290.   if (gcMessage && !regressionTesting) {
  1291.     printf("done\"\n");
  1292.   }
  1293.   gcFlipped = true;
  1294. }
  1295.  
  1296.  
  1297. #ifdef preserved /* Sat Jul 27 16:37:34 1991 */
  1298. /**/void gcFlip()
  1299. /**/{
  1300. /**/  long        oldCopySize, oldNewSize;
  1301. /**/
  1302. /**/  if (!gcState) {
  1303. /**/    errorf("Attempted to do a gcFlip with garbage collector off!");
  1304. /**/    exit(1);
  1305. /**/  }
  1306. /**/
  1307. /**/  if (gcFlipCounter >= 1) {
  1308. /**/    errorf("Attempted to do a gcFlip too soon after a gcFlip!");
  1309. /**/    exit(1);
  1310. /**/  }
  1311. /**/
  1312. /**/
  1313. /**/#ifdef OOP_DEBUGGING
  1314. /**/  printf("%d free oops = %.2f%%, scanner was at %d/%d\n", numFreeOOPs,
  1315. /**/       100.0 * numFreeOOPs / OOP_TABLE_SIZE, oopTableIndex, OOP_TABLE_SIZE);
  1316. /**/#endif
  1317. /**/
  1318. /**/  if (gcMessage && !regressionTesting) {
  1319. /**/    /* print the first part of this message before we finish scanning 
  1320. /**/     * oop table for live ones, so that the delay caused by this scanning
  1321. /**/     * is apparent.
  1322. /**/     */
  1323. /**/    printf("\"GC flipping "); fflush(stdout);
  1324. /**/  }
  1325. /**/
  1326. /**/  finishOOPScan();        /* make sure we're done */
  1327. /**/
  1328. /**/  oldCopySize = curSpace->copyPtr - curSpace->space;
  1329. /**/  oldNewSize = curSpace->space + MEM_SPACE_SIZE - curSpace->allocPtr;
  1330. /**/
  1331. /**/if (oldCopySize == 0) {  /* ### Experimental */
  1332. /**/  oldCopySize = oldNewSize;
  1333. /**/}
  1334. /**/
  1335. /**/
  1336. /**/  copyRate = ((double)oldCopySize) / oldNewSize;
  1337. /**/  copyRate *= copyRateAdjustment;
  1338. /**/
  1339. /**/  toSpace ^= F_SPACE;
  1340. /**/  fromSpace ^= F_SPACE;
  1341. /**/  evenOddFlag ^= EVEN_ODD_MASK;    /* switch which bit is in use */
  1342. /**/#ifdef bogus /* Sat Oct 13 15:38:55 1990 */
  1343. /**//**/  toSpace = !toSpace;
  1344. /**//**/  fromSpace = !fromSpace;
  1345. /**/#endif /* bogus Sat Oct 13 15:38:55 1990 */
  1346. /**/  curSpace = &spaces[boolSpace(toSpace)];
  1347. /**/  curObject = nil;
  1348. /**/  copyQuota = 0;
  1349. /**/  oopTableIndex = 0;
  1350. /**/  initSpace(curSpace);
  1351. /**/
  1352. /**/#ifdef remove_soon /* Mon May 14 23:41:55 1990 */
  1353. /**//**/zeroMarks();
  1354. /**/#endif /* remove_soon Mon May 14 23:41:55 1990 */
  1355. /**/
  1356. /**/  /* note the use of quotation marks around the printed message.  The
  1357. /**/     idea here was to make them appear as Smalltalk comments, so that 
  1358. /**/     generated output could be fed to another Smalltalk without harm. */
  1359. /**/  if (gcMessage && !regressionTesting) {
  1360. /**/    printf("to space %d...", boolSpace(toSpace)); fflush(stdout);
  1361. /**/    printf("copied space = %.1f%%...", oldCopySize * 100.0 / MEM_SPACE_SIZE);
  1362. /**/  }
  1363. /**/  moveRootOOPs();
  1364. /**/  if (gcMessage && !regressionTesting) {
  1365. /**/    printf("done\"\n");
  1366. /**/  }
  1367. /**/  gcFlipped = true;
  1368. /**/}
  1369. #endif /* preserved Sat Jul 27 16:37:34 1991 */
  1370.  
  1371. /*
  1372.  *    static void moveRootOOPs()
  1373.  *
  1374.  * Description
  1375.  *
  1376.  *    Copies the root objects from old space to new space.  All of the root
  1377.  *    objects are those that are mentioned in the set of objects that are
  1378.  *    known specially by the interpreter, those that are being used by the
  1379.  *    interpreter, and some information about compilation state.  Also, the
  1380.  *    built-in oops (Characters, nil, true, false) are marked as being in new
  1381.  *    space so that they won't ever be moved.
  1382.  *
  1383.  */
  1384. static void moveRootOOPs()
  1385. {
  1386.   OOP        **oopPtr, oop;
  1387.  
  1388.   markBuiltinOOPs();
  1389.  
  1390.   /* copy objects that have global pointers */
  1391.   for (oopPtr = globalOOPs; *oopPtr; oopPtr++) {
  1392.     oop = **oopPtr;
  1393.     localMaybeMoveOOP(oop);        /* use the maybe form here so that we don't
  1394.                  * accidentally move builtins, which have
  1395.                  * already been marked as being in the new
  1396.                  * space
  1397.                  */
  1398.   }
  1399.  
  1400.   moveProcessorRegisters();
  1401.  
  1402.   copyRegisteredOOPs();
  1403.  
  1404.   copyCompileContext();
  1405. }
  1406.  
  1407. /*
  1408.  *    static void markBuiltinOOPs()
  1409.  *
  1410.  * Description
  1411.  *
  1412.  *    Marks all of the builtin OOPS (nil, true, false, and the Characters) as
  1413.  *    being in the current new space.
  1414.  *
  1415.  */
  1416. static void markBuiltinOOPs()
  1417. {
  1418.   register OOP    oop;
  1419.  
  1420.  
  1421.   for (oop = &oopTable[OOP_TABLE_SIZE]; oop < &oopTable[TOTAL_OOP_TABLE_SLOTS];
  1422.        oop++) {
  1423.     oop->flags = (oop->flags & ~F_SPACE) | toSpace | F_EVEN | F_ODD;
  1424.   }
  1425. }
  1426.  
  1427. /*
  1428.  *    static void initSpace(space)
  1429.  *
  1430.  * Description
  1431.  *
  1432.  *    Initializes the allocation and copying pointers for semispace SPACE.
  1433.  *
  1434.  * Inputs
  1435.  *
  1436.  *    space : Semispace index number.
  1437.  *
  1438.  */
  1439. static void initSpace(space)
  1440. struct memorySpaceStruct *space;
  1441. {
  1442.   char        *oldSpace;
  1443.   if (space->totalSize < maxSpaceSize) {
  1444.     oldSpace = space->space;
  1445.     space->space = (char *)realloc(oldSpace, maxSpaceSize);
  1446.     if (space->space == NULL) {
  1447.       space->space = oldSpace;
  1448.       errorf("Could not grow space to %d", maxSpaceSize);
  1449.       /* ??? Should print some kind of warning here, like we can't reallocate
  1450.        * more space */
  1451.     } else {
  1452.       space->totalSize = maxSpaceSize;
  1453.     }
  1454.   }
  1455.  
  1456.   space->copyPtr = space->scanPtr = space->space;
  1457.   space->size = space->totalSize;
  1458.   space->allocPtr = space->space + space->size;
  1459. }
  1460.  
  1461.  
  1462. void growBothSpaces(newSize)
  1463. unsigned long newSize;
  1464. {
  1465.   int        i;
  1466.  
  1467.   maxSpaceSize = newSize;
  1468.  
  1469.   for (i = 0; i < 2; i++) {
  1470.     initSpace(&spaces[i]);
  1471.   }
  1472. }
  1473.  
  1474. #ifndef INLINE_MACROS
  1475.  
  1476. /*
  1477.  *    void maybeMoveOOP(oop)
  1478.  *
  1479.  * Description
  1480.  *
  1481.  *    Move OOP to new space if it's not already there.
  1482.  *
  1483.  * Inputs
  1484.  *
  1485.  *    oop   : OOP to be examined, and, if it's in old space, moved to new
  1486.  *        space.
  1487.  *
  1488.  */
  1489. void maybeMoveOOP(oop)
  1490. OOP    oop;
  1491. {
  1492.   maybeMoveOOPMac(oop);
  1493. }
  1494.  
  1495. #endif /* INLINE_MACROS */
  1496.  
  1497.  
  1498. /*
  1499.  *    void moveOOP(oop)
  1500.  *
  1501.  * Description
  1502.  *
  1503.  *    Moves an OOP from old space to new space unconditionally.  Basically
  1504.  *    marks the OOP as being in the current new space, copies the object that
  1505.  *    the oop points to to new space, and sets the even/odd flags to keep the
  1506.  *    OOP table garbage collector from reaping this OOP.
  1507.  *
  1508.  * Inputs
  1509.  *
  1510.  *    oop   : OOP to be moved.  Should always be in OLD space.
  1511.  *
  1512.  */
  1513. void moveOOP(oop)
  1514. OOP    oop;
  1515. {
  1516.   Object    object;
  1517.  
  1518. #ifndef OPTIMIZE
  1519.   if (isFake(oop)) {
  1520.     printf("moving fake object!!! %x\n", oop);
  1521.     debug();
  1522.   }
  1523. #endif /* !OPTIMIZE */
  1524.  
  1525.   object = oopToObj(oop);
  1526.   /* !!! this F_SPACE and TO_SPACE stuff should go */
  1527.   oop->flags = (oop->flags & ~F_SPACE) | toSpace | evenOddFlag;
  1528.   oop->object = moveObject(object);
  1529. }
  1530.  
  1531. /*
  1532.  *    static Object moveObject(object)
  1533.  *
  1534.  * Description
  1535.  *
  1536.  *    Copies OBJECT from old space to new space.  Adjusts the garbage
  1537.  *    collectors pointers to indicate that the object has been added to new
  1538.  *    space so that the scanner will see it.
  1539.  *
  1540.  * Inputs
  1541.  *
  1542.  *    object: Object to be moved to new space.
  1543.  *
  1544.  */
  1545. static Object moveObject(object)
  1546. Object    object;
  1547. {
  1548.   long        size;
  1549.  
  1550. /* dprintf("moving %8x, size %d\n", curSpace->copyPtr, object->objSize); */
  1551. if ((long) object->objSize  >= 1000) {
  1552.   debug();
  1553. }
  1554.   size = object->objSize * sizeof(OOP);
  1555.   memcpy(curSpace->copyPtr, object, size);
  1556.   object = (Object)curSpace->copyPtr;
  1557.   curSpace->copyPtr += size;
  1558.   curSpace->size -= size;
  1559.   if (curSpace->copyPtr >= curSpace->allocPtr) {
  1560.     errorf("Garbage collector failed...ran out of room while copying!!!");
  1561.     exit(0);
  1562.   }
  1563.  
  1564.   return (object);
  1565. }
  1566.  
  1567. #ifdef pre_full_gc /* Sun Aug  4 19:31:08 1991 */
  1568. /**//*
  1569. /**/ *    void printFreeList()
  1570. /**/ *
  1571. /**/ * Description
  1572. /**/ *
  1573. /**/ *    Debugging support routine.  Prints the free list.  Meant only to be
  1574. /**/ *    called from a debugger.
  1575. /**/ *
  1576. /**/ */
  1577. /**/void printFreeList()
  1578. /**/{
  1579. /**/  OOP        oop;
  1580. /**/  for (oop = freeOOPs; oop != nil; oop = (OOP)oop->object) {
  1581. /**/    printf("oop %x\n", oop);
  1582. /**/    printf("oop isfree %d\n", (oop->flags & F_FREE) != 0);
  1583. /**/  }
  1584. /**/}
  1585. #endif /* pre_full_gc Sun Aug  4 19:31:08 1991 */
  1586.  
  1587. /*
  1588.  *    debug()
  1589.  *
  1590.  * Description
  1591.  *
  1592.  *    Used for debugging.  You set a breakpoint in the debug routine in the
  1593.  *    debugger, and have code call it when you want it to stop.  Performs no
  1594.  *    action normally.
  1595.  *
  1596.  */
  1597. debug()
  1598. {
  1599. }
  1600.  
  1601.  
  1602. #ifdef remove_soon /* Mon May 14 23:42:01 1990 */
  1603. /**/static void zeroMarks()
  1604. /**/{
  1605. /**/  char    *p;
  1606. /**/
  1607. /**/  for (p = marks; p < &marks[TOTAL_OOP_TABLE_SLOTS]; ) {
  1608. /**/    *p++ = 0;
  1609. /**/  }
  1610. /**/}
  1611. #endif /* remove_soon Mon May 14 23:42:01 1990 */
  1612.