home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mitsch75.zip / scheme-7_5_17-src.zip / scheme-7.5.17 / src / microcode / gccode.h < prev    next >
C/C++ Source or Header  |  2000-12-05  |  17KB  |  575 lines

  1. /* -*-C-*-
  2.  
  3. $Id: gccode.h,v 9.57 2000/12/05 21:23:44 cph Exp $
  4.  
  5. Copyright (c) 1987-2000 Massachusetts Institute of Technology
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or (at
  10. your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful, but
  13. WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15. General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21.  
  22. /* This file contains the macros for use in code which does GC-like
  23.    loops over memory.  It is only included in a few files, unlike
  24.    gc.h which contains general purpose macros and constants. */
  25.  
  26. #ifdef ENABLE_DEBUGGING_TOOLS
  27. #ifndef ENABLE_GC_DEBUGGING_TOOLS
  28. #define ENABLE_GC_DEBUGGING_TOOLS
  29. #endif
  30. #endif
  31.  
  32. /* A SWITCH on GC types, duplicates information in GC_Type_Map[], but
  33.    exists for efficiency reasons. Macros must be used by convention:
  34.    first Switch_by_GC_Type, then each of the case_ macros (in any
  35.    order).  The default: case MUST be included in the switch. */
  36.  
  37. #define Switch_by_GC_Type(P)                        \
  38.   switch (OBJECT_TYPE (P))
  39.  
  40. #define case_simple_Non_Pointer                        \
  41.   case TC_NULL:                                \
  42.   case TC_CONSTANT:                            \
  43.   case TC_RETURN_CODE:                            \
  44.   case TC_THE_ENVIRONMENT
  45.  
  46. #define case_Fasload_Non_Pointer                    \
  47.   case_TC_FIXNUMs:                            \
  48.   case TC_CHARACTER:                            \
  49.   case_simple_Non_Pointer
  50.  
  51. #define case_Non_Pointer                        \
  52.   case TC_PRIMITIVE:                            \
  53.   case TC_PCOMB0:                            \
  54.   case TC_STACK_ENVIRONMENT:                        \
  55.   case_Fasload_Non_Pointer
  56.  
  57. /* Missing Non Pointer types (must always be treated specially):
  58.    TC_BROKEN_HEART
  59.    TC_MANIFEST_NM_VECTOR
  60.    TC_MANIFEST_SPECIAL_NM_VECTOR
  61.    TC_REFERENCE_TRAP
  62.    TC_MANIFEST_CLOSURE
  63.    TC_LINKAGE_SECTION 
  64.  */
  65.  
  66. #define case_compiled_entry_point                    \
  67.  case TC_COMPILED_ENTRY
  68.  
  69. #define case_Cell                            \
  70.  case TC_CELL
  71.  
  72. /* No missing Cell types */
  73.  
  74. #define case_Fasdump_Pair                        \
  75.  case TC_LIST:                                \
  76.  case TC_SCODE_QUOTE:                            \
  77.  case TC_COMBINATION_1:                            \
  78.  case TC_EXTENDED_PROCEDURE:                        \
  79.  case TC_PROCEDURE:                            \
  80.  case TC_DELAY:                                \
  81.  case TC_DELAYED:                            \
  82.  case TC_COMMENT:                            \
  83.  case TC_LAMBDA:                            \
  84.  case TC_SEQUENCE_2:                            \
  85.  case TC_PCOMB1:                            \
  86.  case TC_ACCESS:                            \
  87.  case TC_DEFINITION:                            \
  88.  case TC_ASSIGNMENT:                            \
  89.  case TC_IN_PACKAGE:                            \
  90.  case TC_LEXPR:                                \
  91.  case TC_DISJUNCTION:                            \
  92.  case TC_COMPLEX:                            \
  93.  case TC_ENTITY:                            \
  94.  case TC_RATNUM
  95.  
  96. #define case_Pair                            \
  97.  case TC_INTERNED_SYMBOL:                        \
  98.  case TC_UNINTERNED_SYMBOL:                        \
  99.  case_Fasdump_Pair
  100.  
  101. /* Missing pair types (must be treated specially):
  102.    TC_WEAK_CONS 
  103.  */
  104.  
  105. #define case_Triple                            \
  106.  case TC_COMBINATION_2:                            \
  107.  case TC_EXTENDED_LAMBDA:                        \
  108.  case TC_HUNK3_A:                            \
  109.  case TC_HUNK3_B:                            \
  110.  case TC_CONDITIONAL:                            \
  111.  case TC_SEQUENCE_3:                            \
  112.  case TC_PCOMB2
  113.  
  114. /* Missing triple types (must be treated specially):
  115.    TC_VARIABLE */
  116.  
  117. #define case_Quadruple                            \
  118.   case TC_QUAD
  119.  
  120. /* No missing quad types. */
  121.  
  122. #define case_simple_Vector                        \
  123.  case TC_NON_MARKED_VECTOR:                        \
  124.  case TC_VECTOR:                            \
  125.  case TC_RECORD:                            \
  126.  case TC_CONTROL_POINT:                            \
  127.  case TC_COMBINATION:                            \
  128.  case TC_PCOMB3:                            \
  129.  case TC_VECTOR_1B:                            \
  130.  case TC_VECTOR_16B
  131.  
  132. #define case_Purify_Vector                        \
  133.  case TC_BIG_FIXNUM:                            \
  134.  case TC_CHARACTER_STRING:                        \
  135.  case_simple_Vector
  136.  
  137. #define case_Vector                            \
  138.  case TC_ENVIRONMENT:                            \
  139.  case_Purify_Vector
  140.  
  141. #define case_Aligned_Vector                        \
  142.  case TC_COMPILED_CODE_BLOCK:                        \
  143.  case TC_BIG_FLONUM
  144.  
  145. /* Missing vector types (must be treated specially):
  146.    TC_FUTURE 
  147.  */
  148.  
  149. extern char gc_death_message_buffer [];
  150.  
  151. extern void
  152.   EXFUN (gc_death, (long code, char *, SCHEME_OBJECT *, SCHEME_OBJECT *));
  153.  
  154. /* Assumption: A call to GC_BAD_TYPE is followed by the non-pointer code. */
  155.  
  156. #ifndef BAD_TYPES_INNOCUOUS
  157.  
  158. #define GC_BAD_TYPE(name, object) do                    \
  159. {                                    \
  160.   sprintf                                \
  161.     (gc_death_message_buffer,                        \
  162.      "%s: bad type code (0x%02lx)",                    \
  163.      (name),                                \
  164.      (OBJECT_TYPE (object)));                        \
  165.   gc_death                                \
  166.     (TERM_INVALID_TYPE_CODE,                        \
  167.      gc_death_message_buffer,                        \
  168.      Scan,                                \
  169.      To);                                \
  170.   /*NOTREACHED*/                            \
  171. } while (0)
  172.  
  173. #else /* BAD_TYPES_INNOCUOUS */
  174.  
  175. #define GC_BAD_TYPE(name, object) do                    \
  176. {                                    \
  177.   outf_error ("\n%s: bad type code (0x%02lx) 0x%lx",            \
  178.      (name),                                \
  179.      (OBJECT_TYPE (object)),                        \
  180.      (object));                                \
  181.   outf_error (" -- Treating as non-pointer.\n");            \
  182.   /* Fall through */                            \
  183. } while (0)
  184.  
  185. #endif /* BAD_TYPES_INNOCUOUS */
  186.  
  187. /* Macros for the garbage collector and related programs. */
  188.  
  189. /* Pointer setup for the GC Type handlers. */
  190.  
  191. #define GC_Consistency_Check(In_GC)                    \
  192. {                                    \
  193.   if And2 (In_GC, Consistency_Check)                    \
  194.   {                                    \
  195.     if ((Old >= Highest_Allocated_Address)                \
  196.     || (Old < Lowest_Allocated_Address))                \
  197.     {                                    \
  198.       sprintf                                \
  199.     (gc_death_message_buffer,                    \
  200.      "setup_internal: out of range pointer (0x%lx)",        \
  201.      Temp);                                \
  202.       gc_death (TERM_EXIT, gc_death_message_buffer, Scan, To);        \
  203.       /*NOTREACHED*/                            \
  204.     }                                    \
  205.   }                                    \
  206. }
  207.  
  208. /* Check whether it has been relocated. */
  209.  
  210. #define Normal_BH(In_GC, then_what)                    \
  211. {                                    \
  212.   if (BROKEN_HEART_P (* Old))                        \
  213.   {                                    \
  214.     (* Scan) = (MAKE_OBJECT_FROM_OBJECTS (Temp, (* Old)));        \
  215.     then_what;                                \
  216.   }                                    \
  217. }
  218.  
  219. #define RAW_BH(In_GC, then_what)                    \
  220. {                                    \
  221.   if (BROKEN_HEART_P (* Old))                        \
  222.   {                                    \
  223.     (* Scan) = (ADDR_TO_SCHEME_ADDR (OBJECT_ADDRESS (* Old)));        \
  224.     then_what;                                \
  225.   }                                    \
  226. }
  227.  
  228. #define Setup_Internal(In_GC, Transport_Code, Already_Relocated_Code)    \
  229. {                                    \
  230.   GC_Consistency_Check (In_GC);                        \
  231.   if (Old < low_heap)                            \
  232.     continue;                                \
  233.   Already_Relocated_Code;                        \
  234.   New_Address = (MAKE_BROKEN_HEART (To));                \
  235.   Transport_Code;                            \
  236. }
  237.  
  238. #define Setup_Aligned(In_GC, Transport_Code, Already_Relocated_Code)    \
  239. {                                    \
  240.   GC_Consistency_Check (In_GC);                        \
  241.   if (Old < low_heap)                            \
  242.     continue;                                \
  243.   Already_Relocated_Code;                        \
  244.   ALIGN_FLOAT (To);                            \
  245.   New_Address = (MAKE_BROKEN_HEART (To));                \
  246.   Transport_Code;                            \
  247. }
  248.  
  249. #define Setup_Pointer(In_GC, Transport_Code)                \
  250. {                                    \
  251.   Setup_Internal (In_GC, Transport_Code, Normal_BH (In_GC, continue));    \
  252. }
  253.  
  254. #define Pointer_End()                            \
  255. {                                    \
  256.   (* (OBJECT_ADDRESS (Temp))) = New_Address;                \
  257.   (* Scan) = (MAKE_OBJECT_FROM_OBJECTS (Temp, New_Address));        \
  258. }
  259.  
  260. /* HP sucks the big donkey wong?! (still?) */
  261. /* HP92453-01 A.09.19 HP C Compiler on HP-UX 9.01 drops the
  262.    first line when "optimizing".
  263.  */
  264.  
  265. #if defined(hp9000s800) || defined(__hp9000s800)
  266. SCHEME_OBJECT gccode_HPUX_lossage_bug_fix_fnord; /* ``I'm not dead yet!'' */
  267.  
  268. #define RAW_POINTER_END()                        \
  269. {                                    \
  270.   gccode_HPUX_lossage_bug_fix_fnord = Temp;                \
  271.   (* (SCHEME_ADDR_TO_ADDR (gccode_HPUX_lossage_bug_fix_fnord)))         \
  272.     = New_Address;                            \
  273.   (* Scan) = (ADDR_TO_SCHEME_ADDR (OBJECT_ADDRESS (New_Address)));    \
  274. }
  275. #else /* not hp9000s800 */
  276. #define RAW_POINTER_END()                        \
  277. {                                    \
  278.   (* (SCHEME_ADDR_TO_ADDR (Temp))) = New_Address;            \
  279.   (* Scan) = (ADDR_TO_SCHEME_ADDR (OBJECT_ADDRESS (New_Address)));    \
  280. }
  281. #endif /* hp9000s800 */
  282.  
  283. /* GC Type handlers.  These do the actual work. */
  284.  
  285. #ifdef ENABLE_GC_DEBUGGING_TOOLS
  286.  
  287. extern SCHEME_OBJECT gc_object_referenced;
  288. extern SCHEME_OBJECT gc_objects_referencing;
  289. extern unsigned long gc_objects_referencing_count;
  290. extern SCHEME_OBJECT * gc_objects_referencing_scan;
  291. extern SCHEME_OBJECT * gc_objects_referencing_end;
  292.  
  293. #define TRANSPORT_ONE_THING(transport_code)                \
  294. {                                    \
  295.   if ((gc_object_referenced == (*Old))                    \
  296.       && (gc_objects_referencing != SHARP_F))                \
  297.     {                                    \
  298.       gc_objects_referencing_count += 1;                \
  299.       if (gc_objects_referencing_scan != gc_objects_referencing_end)    \
  300.     {                                \
  301.       UPDATE_GC_OBJECTS_REFERENCING ();                \
  302.       (*gc_objects_referencing_scan++) = object_referencing;    \
  303.     }                                \
  304.     }                                    \
  305.   transport_code;                            \
  306. }
  307.  
  308. #define UPDATE_GC_OBJECTS_REFERENCING()                    \
  309. {                                    \
  310.   if (BROKEN_HEART_P (MEMORY_REF (gc_objects_referencing, 0)))        \
  311.     {                                    \
  312.       SCHEME_OBJECT new =                        \
  313.     (MAKE_OBJECT_FROM_OBJECTS                    \
  314.      (gc_objects_referencing,                    \
  315.       (MEMORY_REF (gc_objects_referencing, 0))));            \
  316.       gc_objects_referencing_scan =                    \
  317.     (VECTOR_LOC                            \
  318.      (new,                                \
  319.       (gc_objects_referencing_scan                    \
  320.        - (VECTOR_LOC (gc_objects_referencing, 0)))));        \
  321.       gc_objects_referencing_end =                    \
  322.     (VECTOR_LOC (new, (VECTOR_LENGTH (new))));            \
  323.       gc_objects_referencing = new;                    \
  324.     }                                    \
  325. }
  326.  
  327. #else
  328.  
  329. #define TRANSPORT_ONE_THING(transport_code) transport_code
  330.  
  331. #endif
  332.  
  333. #define Transport_Cell()                        \
  334. {                                    \
  335.   TRANSPORT_ONE_THING ((*To++) = (*Old));                \
  336.   Pointer_End ();                            \
  337. }
  338.  
  339. #define Transport_Pair()                        \
  340. {                                    \
  341.   TRANSPORT_ONE_THING ((*To++) = (*Old++));                \
  342.   TRANSPORT_ONE_THING ((*To++) = (*Old));                \
  343.   Pointer_End ();                            \
  344. }
  345.  
  346. #define Transport_Triple()                        \
  347. {                                    \
  348.   TRANSPORT_ONE_THING ((*To++) = (*Old++));                \
  349.   TRANSPORT_ONE_THING ((*To++) = (*Old++));                \
  350.   TRANSPORT_ONE_THING ((*To++) = (*Old));                \
  351.   Pointer_End ();                            \
  352. }
  353.  
  354. #define TRANSPORT_QUADRUPLE_INTERNAL()                    \
  355. {                                    \
  356.   TRANSPORT_ONE_THING ((*To++) = (*Old++));                \
  357.   TRANSPORT_ONE_THING ((*To++) = (*Old++));                \
  358.   TRANSPORT_ONE_THING ((*To++) = (*Old++));                \
  359.   TRANSPORT_ONE_THING ((*To++) = (*Old));                \
  360. }
  361.  
  362. #define Transport_Quadruple()                        \
  363. {                                    \
  364.   TRANSPORT_QUADRUPLE_INTERNAL ();                    \
  365.   Pointer_End ();                            \
  366. }
  367.  
  368. #define TRANSPORT_RAW_QUADRUPLE()                    \
  369. {                                    \
  370.   TRANSPORT_QUADRUPLE_INTERNAL ();                    \
  371.   RAW_POINTER_END ();                            \
  372. }
  373.  
  374. #ifndef In_Fasdump
  375.  
  376. /* The OBJECT_DATUM below gets the length of the vector.
  377.    (VECTOR_LENGTH (Temp)) cannot be used because Temp does
  378.    not necessarily point to the first word of the object.
  379.    Currently only compiled entry points point to the
  380.    "middle" of vectors. */
  381.  
  382. #ifdef ENABLE_GC_DEBUGGING_TOOLS
  383.  
  384. extern void EXFUN (check_transport_vector_lossage,
  385.            (SCHEME_OBJECT *, SCHEME_OBJECT *, SCHEME_OBJECT *));
  386.  
  387. #define CHECK_TRANSPORT_VECTOR_TERMINATION()                \
  388. {                                    \
  389.   if (! ((To <= Scan)                            \
  390.      && (((Constant_Space <= To) && (To < Heap_Bottom))        \
  391.          ? ((Constant_Space <= Scan) && (Scan < Heap_Bottom))    \
  392.          : ((Heap_Bottom <= Scan) && (Scan < Heap_Top)))))        \
  393.     check_transport_vector_lossage (Scan, Saved_Scan, To);        \
  394.   if ((OBJECT_DATUM (*Old)) > 65536)                    \
  395.     {                                    \
  396.       outf_error ("\nWarning: copying large vector: %ld\n",        \
  397.               (OBJECT_DATUM (*Old)));                \
  398.       outf_flush_error ();                        \
  399.     }                                    \
  400. }
  401.  
  402. #else /* not ENABLE_GC_DEBUGGING_TOOLS */
  403.  
  404. #define CHECK_TRANSPORT_VECTOR_TERMINATION()
  405.  
  406. #endif /* not ENABLE_GC_DEBUGGING_TOOLS */
  407.  
  408. #define Real_Transport_Vector()                        \
  409. {                                    \
  410.   SCHEME_OBJECT * Saved_Scan;                        \
  411.                                     \
  412.   Saved_Scan = Scan;                            \
  413.   Scan = (To + 1 + (OBJECT_DATUM (* Old)));                \
  414.   if ((Consistency_Check)                        \
  415.       && (Scan > Heap_Top)                        \
  416.       && (To < Heap_Top)                        \
  417.       && (To >= Heap_Bottom))                        \
  418.     {                                    \
  419.       sprintf                                \
  420.     (gc_death_message_buffer,                    \
  421.      "real_transport_vector: vector length too large (%ld)",    \
  422.      (OBJECT_DATUM (*Old)));                    \
  423.       gc_death (TERM_EXIT, gc_death_message_buffer, Saved_Scan, To);    \
  424.     }                                    \
  425.   CHECK_TRANSPORT_VECTOR_TERMINATION ();                \
  426.   while (To != Scan)                            \
  427.     TRANSPORT_ONE_THING ((*To++) = (*Old++));                \
  428.   Scan = Saved_Scan;                            \
  429. }
  430.  
  431. #else /* In_Fasdump */
  432.  
  433. #define Real_Transport_Vector()                        \
  434. {                                    \
  435.   SCHEME_OBJECT * Saved_Scan;                        \
  436.                                     \
  437.   Saved_Scan = Scan;                            \
  438.   Scan = (To + 1 + (OBJECT_DATUM (*Old)));                \
  439.   if (Scan >= Fixes)                            \
  440.     {                                    \
  441.       Scan = Saved_Scan;                        \
  442.       NewFree = To;                            \
  443.       Fixup = Fixes;                            \
  444.       return (PRIM_INTERRUPT);                        \
  445.     }                                    \
  446.   while (To != Scan)                            \
  447.     TRANSPORT_ONE_THING ((*To++) = (*Old++));                \
  448.   Scan = Saved_Scan;                            \
  449. }
  450.  
  451. #endif
  452.  
  453. #define Transport_Vector()                        \
  454. {                                    \
  455. Move_Vector:                                \
  456.   Real_Transport_Vector ();                        \
  457.   Pointer_End ();                            \
  458. }
  459.  
  460. #define Transport_Future()                        \
  461. {                                    \
  462.   if (! (Future_Spliceable (Temp)))                    \
  463.     goto Move_Vector;                            \
  464.   (*Scan) = (Future_Value (Temp));                    \
  465.   Scan -= 1;                                \
  466. }
  467.  
  468. /* Weak Pointer code.  The idea here is to support a post-GC pass which
  469.    removes any objects in the CAR of a WEAK_CONS cell which is no longer
  470.    referenced by other objects in the system.
  471.  
  472.    The idea is to maintain a (C based) list of weak conses in old
  473.    space.  The head of this list is the variable Weak_Chain.  During
  474.    the normal GC pass, weak cons cells are not copied in the normal
  475.    manner. Instead the following structure is built:
  476.  
  477.      Old Space             |          New Space
  478.  _______________________   |   _______________________
  479.  |Broken |     New     |   |   | NULL | Old CAR data |
  480.  |Heart  |  Location ======|==>|      |              |
  481.  |_______|_____________|   |   |______|______________|
  482.  |Old Car| Next in     |   |   |  Old CDR component  |
  483.  | type  |  chain      |   |   |                     |
  484.  |_____________________|   |   |_____________________|
  485.  
  486.  */
  487.  
  488. extern SCHEME_OBJECT Weak_Chain;
  489.  
  490. #define EMPTY_WEAK_CHAIN   (OBJECT_NEW_TYPE(TC_NULL, 0))
  491.  
  492. #define Transport_Weak_Cons()                        \
  493. {                                    \
  494.   long Car_Type = (OBJECT_TYPE (*Old));                    \
  495.   (*To++) = (OBJECT_NEW_TYPE (TC_NULL, (*Old)));            \
  496.   Old += 1;                                \
  497.   TRANSPORT_ONE_THING ((*To++) = (*Old));                \
  498.   *Old = (OBJECT_NEW_TYPE (Car_Type, Weak_Chain));            \
  499.   Weak_Chain = Temp;                            \
  500.   Pointer_End ();                            \
  501. }
  502.  
  503. /* Special versions of the above for DumpLoop in Fasdump.  This code
  504.    only differs from the code above in that it must check whether
  505.    there is enough space to remember the fixup. */
  506.  
  507. #define Fasdump_Setup_Pointer(Extra_Code, BH_Code)            \
  508. {                                    \
  509.   BH_Code;                                \
  510.                                     \
  511.   /* It must be transported to New Space */                \
  512.                                     \
  513.   New_Address = (MAKE_BROKEN_HEART (To));                \
  514.   if ((Fixes - To) < FASDUMP_FIX_BUFFER)                \
  515.     {                                    \
  516.       NewFree = To;                            \
  517.       Fixup = Fixes;                            \
  518.       return (PRIM_INTERRUPT);                        \
  519.     }                                    \
  520.   (*--Fixes) = (* Old);                            \
  521.   (*--Fixes) = (ADDRESS_TO_DATUM (Old));                \
  522.   Extra_Code;                                \
  523. }
  524.  
  525. #define Fasdump_Setup_Aligned(Extra_Code, BH_Code)            \
  526. {                                    \
  527.   BH_Code;                                \
  528.                                     \
  529.   /* It must be transported to New Space */                \
  530.                                     \
  531.   ALIGN_FLOAT (To);                            \
  532.   New_Address = (MAKE_BROKEN_HEART (To));                \
  533.   if ((Fixes - To) < FASDUMP_FIX_BUFFER)                \
  534.     {                                    \
  535.       NewFree = To;                            \
  536.       Fixup = Fixes;                            \
  537.       return (PRIM_INTERRUPT);                        \
  538.     }                                    \
  539.   (*--Fixes) = (* Old);                            \
  540.   (*--Fixes) = (ADDRESS_TO_DATUM (Old));                \
  541.   Extra_Code;                                \
  542. }
  543.  
  544. /* Undefine Symbols */
  545.  
  546. #define Fasdump_Symbol(global_value)                    \
  547. {                                    \
  548.   (*To++) = (* Old);                            \
  549.   (*To++) = global_value;                        \
  550.   Pointer_End ();                            \
  551. }
  552.  
  553. #define Fasdump_Variable()                        \
  554. {                                    \
  555.   (*To++) = (* Old);                            \
  556.   (*To++) = UNCOMPILED_VARIABLE;                    \
  557.   (*To++) = SHARP_F;                            \
  558.   Pointer_End ();                            \
  559. }
  560.  
  561. /* Compiled Code Relocation Utilities */
  562.  
  563. #include "cmpgc.h"
  564.  
  565. typedef struct gc_hook_list_s
  566. {
  567.   void EXFUN ((* hook), (void));
  568.   struct gc_hook_list_s * next;
  569. } * gc_hook_list;
  570.  
  571. extern int EXFUN (add_pre_gc_hook, (void (*) (void)));
  572. extern int EXFUN (add_post_gc_hook, (void (*) (void)));
  573. extern void EXFUN (run_pre_gc_hooks, (void));
  574. extern void EXFUN (run_post_gc_hooks, (void));
  575.