GC_API void * GC_CALL GC_clear_stack(void *arg)
{
# ifndef STACK_NOT_SCANNED
    ptr_t sp = GC_approx_sp();  /* Hotter than actual sp */
#   ifdef THREADS
        word volatile dummy[SMALL_CLEAR_SIZE];
        static unsigned random_no = 0;
                                /* Should be more random than it is ... */
                                /* Used to occasionally clear a bigger  */
                                /* chunk.                               */
#   endif
    ptr_t limit;

#   define SLOP 400
        /* Extra bytes we clear every time.  This clears our own        */
        /* activation record, and should cause more frequent            */
        /* clearing near the cold end of the stack, a good thing.       */
#   define GC_SLOP 4000
        /* We make GC_high_water this much hotter than we really saw    */
        /* it, to cover for GC noise etc. above our current frame.      */
#   define CLEAR_THRESHOLD 100000
        /* We restart the clearing process after this many bytes of     */
        /* allocation.  Otherwise very heavily recursive programs       */
        /* with sparse stacks may result in heaps that grow almost      */
        /* without bounds.  As the heap gets larger, collection         */
        /* frequency decreases, thus clearing frequency would decrease, */
        /* thus more junk remains accessible, thus the heap gets        */
        /* larger ...                                                   */
#   ifdef THREADS
      if (++random_no % 13 == 0) {
        limit = sp;
        MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word));
        limit = (ptr_t)((word)limit & ~0xf);
                        /* Make it sufficiently aligned for assembly    */
                        /* implementations of GC_clear_stack_inner.     */
        return GC_clear_stack_inner(arg, limit);
      } else {
        BZERO((void *)dummy, SMALL_CLEAR_SIZE*sizeof(word));
      }
#   else
      if (GC_gc_no > GC_stack_last_cleared) {
        /* Start things over, so we clear the entire stack again */
        if (GC_stack_last_cleared == 0)
          GC_high_water = (ptr_t)GC_stackbottom;
        GC_min_sp = GC_high_water;
        GC_stack_last_cleared = GC_gc_no;
        GC_bytes_allocd_at_reset = GC_bytes_allocd;
      }
      /* Adjust GC_high_water */
      MAKE_COOLER(GC_high_water, WORDS_TO_BYTES(DEGRADE_RATE) + GC_SLOP);
      if ((word)sp HOTTER_THAN (word)GC_high_water) {
          GC_high_water = sp;
      }
      MAKE_HOTTER(GC_high_water, GC_SLOP);
      limit = GC_min_sp;
      MAKE_HOTTER(limit, SLOP);
      if ((word)sp COOLER_THAN (word)limit) {
        limit = (ptr_t)((word)limit & ~0xf);
                        /* Make it sufficiently aligned for assembly    */
                        /* implementations of GC_clear_stack_inner.     */
        GC_min_sp = sp;
        return GC_clear_stack_inner(arg, limit);
      } else if (GC_bytes_allocd - GC_bytes_allocd_at_reset
                    > CLEAR_THRESHOLD) {
        /* Restart clearing process, but limit how much clearing we do. */
        GC_min_sp = sp;
        MAKE_HOTTER(GC_min_sp, CLEAR_THRESHOLD/4);
        if ((word)GC_min_sp HOTTER_THAN (word)GC_high_water)
          GC_min_sp = GC_high_water;
        GC_bytes_allocd_at_reset = GC_bytes_allocd;
      }
#   endif
# endif
  return arg;
}