Esempio n. 1
0
inline static void mark_threads(NewGC *gc, int owner)
{
  GC_Thread_Info *work;
  Mark2_Proc thread_mark = gc->mark_table[btc_redirect_thread];

  for(work = gc->thread_infos; work; work = work->next) {
    if (work->owner == owner) {
      if (((Scheme_Object *)work->thread)->type == scheme_thread_type) {
        /* thread */
        if (((Scheme_Thread *)work->thread)->running) {
          thread_mark(work->thread, gc);
          if (work->thread == scheme_current_thread) {
            GC_mark_variable_stack(GC_variable_stack, 0, get_stack_base(gc), NULL);
          }
        }
      } else {
        /* place */
#ifdef MZ_USE_PLACES
        /* add in the memory used by the place's GC */
        intptr_t sz;
        Scheme_Place_Object *place_obj = ((Scheme_Place *)work->thread)->place_obj;
        if (place_obj) {
          mzrt_mutex_lock(place_obj->lock);
          sz = place_obj->memory_use;
          mzrt_mutex_unlock(place_obj->lock);
          account_memory(gc, owner, gcBYTES_TO_WORDS(sz), 0);
        }
#endif
      }
    }
  }
}
Esempio n. 2
0
static int size_weak_array(void *p, struct NewGC *gc)
{
  GC_Weak_Array *a = (GC_Weak_Array *)p;

  return gcBYTES_TO_WORDS(sizeof(GC_Weak_Array) 
			  + ((a->count - 1 + 1) * sizeof(void *)));
}
Esempio n. 3
0
static int mark_ephemeron(void *p, struct NewGC *gc)
{
  GC_Ephemeron *eph = (GC_Ephemeron *)p;

  if (eph->val) {
    GC_ASSERT(!gc->doing_memory_accounting);
    if (gc->inc_gen1) {
      eph->inc_next = gc->inc_ephemerons;
      gc->inc_ephemerons = eph;
    } else if (gc->during_backpointer) {
      if (!gc->gc_full
          /* If this old-generation object is not yet marked
             and we're finishing an incremental pass, then
             it won't get marked (and it can only refer to
             other old-generation objects), so ignore in that case */
          && (gc->mark_gen1
              || !gc->started_incremental
              || !gc->finishing_incremental)) {
        eph->next = gc->bp_ephemerons;
        gc->bp_ephemerons = eph;
      }
    } else {
      eph->next = gc->ephemerons;
      gc->ephemerons = eph;
    }
  }

  return gcBYTES_TO_WORDS(sizeof(GC_Ephemeron));
}
Esempio n. 4
0
static int mark_weak_array(void *p, struct NewGC *gc)
{
  GC_Weak_Array *a = (GC_Weak_Array *)p;

  gcMARK2(a->replace_val, gc);

  a->next = gc->weak_arrays;
  gc->weak_arrays = a;

#if CHECKS
  /* For now, weak arrays only used for symbols, keywords, and falses: */
  {
    void **data;
    int i;
    data = a->data;
    for (i = a->count; i--; ) {
      if (data[i] 
	  && (*(short *)(data[i]) != 48)
	  && (*(short *)(data[i]) != 49)
	  && (*(short *)(data[i]) != 58)) {
	CRASH(1);
      }
    }
  }
#endif

  return gcBYTES_TO_WORDS(sizeof(GC_Weak_Array) 
			  + ((a->count - 1) * sizeof(void *)));
}
Esempio n. 5
0
inline static void BTC_memory_account_mark(NewGC *gc, mpage *page, void *ptr)
{
  GCDEBUG((DEBUGOUTF, "BTC_memory_account_mark: %p/%p\n", page, ptr));
  if(page->size_class) {
    if(page->size_class > 1) {
      /* big page */
      objhead *info = BIG_PAGE_TO_OBJHEAD(page);
      
      if(info->btc_mark == gc->old_btc_mark) {
        info->btc_mark = gc->new_btc_mark;
        account_memory(gc, gc->current_mark_owner, gcBYTES_TO_WORDS(page->size));
        push_ptr(gc, TAG_AS_BIG_PAGE_PTR(ptr));
      }
    } else {
      /* medium page */
      objhead *info = MED_OBJHEAD(ptr, page->size);

      if(info->btc_mark == gc->old_btc_mark) {
        info->btc_mark = gc->new_btc_mark;
        account_memory(gc, gc->current_mark_owner, info->size);
        ptr = OBJHEAD_TO_OBJPTR(info);
        push_ptr(gc, ptr);
      }
    }
  } else {
    objhead *info = OBJPTR_TO_OBJHEAD(ptr);

    if(info->btc_mark == gc->old_btc_mark) {
      info->btc_mark = gc->new_btc_mark;
      account_memory(gc, gc->current_mark_owner, info->size);
      push_ptr(gc, ptr);
    }
  }
}
Esempio n. 6
0
static int fixup_ephemeron(void *p)
{
  GC_Ephemeron *eph = (GC_Ephemeron *)p;
    
  gcFIXUP(eph->key);
  gcFIXUP(eph->val);

  return gcBYTES_TO_WORDS(sizeof(GC_Ephemeron));
}
Esempio n. 7
0
static int btc_mark_ephemeron(void *p)
{
  GC_Ephemeron *eph = (GC_Ephemeron *)p;
  
  gcMARK(eph->key);
  gcMARK(eph->val);

  return gcBYTES_TO_WORDS(sizeof(GC_Ephemeron));
}
Esempio n. 8
0
static int fixup_weak_box(void *p)
{
  GC_Weak_Box *wb = (GC_Weak_Box *)p;
    
  gcFIXUP(wb->secondary_erase);
  gcFIXUP(wb->val);

  return gcBYTES_TO_WORDS(sizeof(GC_Weak_Box));
}
Esempio n. 9
0
static int fixup_ephemeron(void *p, struct NewGC *gc)
{
  GC_Ephemeron *eph = (GC_Ephemeron *)p;
    
  gcFIXUP2(eph->key, gc);
  gcFIXUP2(eph->val, gc);

  return gcBYTES_TO_WORDS(sizeof(GC_Ephemeron));
}
Esempio n. 10
0
int BTC_bi_chan_mark(void *p, struct NewGC *gc)
{
  if (gc->doing_memory_accounting) {
    Scheme_Place_Bi_Channel *bc = (Scheme_Place_Bi_Channel *)p;
    /* The `link` field can be NULL if the channel is still being
       set up: */
    if (bc->link) {
      /* Race conditions here on `mem_size', and likely double counting
         when the same async channels are accessible from paired bi
         channels --- but those approximations are ok for accounting. */
      if (bc->link->sendch)
        account_memory(gc, gc->current_mark_owner, gcBYTES_TO_WORDS(bc->link->sendch->mem_size), 0);
      if (bc->link->recvch)
        account_memory(gc, gc->current_mark_owner, gcBYTES_TO_WORDS(bc->link->recvch->mem_size), 0);
    }
  }
  return gc->mark_table[btc_redirect_bi_chan](p, gc);
}
Esempio n. 11
0
static int fixup_weak_box(void *p, struct NewGC *gc)
{
  GC_Weak_Box *wb = (GC_Weak_Box *)p;
    
  gcFIXUP2(wb->secondary_erase, gc);
  gcFIXUP2(wb->val, gc);

  return gcBYTES_TO_WORDS(sizeof(GC_Weak_Box));
}
Esempio n. 12
0
static int mark_ephemeron(void *p)
{
  GC_Ephemeron *eph = (GC_Ephemeron *)p;

  if (eph->val) {
    eph->next = ephemerons;
    ephemerons = eph;
  }

  return gcBYTES_TO_WORDS(sizeof(GC_Ephemeron));
}
Esempio n. 13
0
static int mark_ephemeron(void *p, struct NewGC *gc)
{
  GC_Ephemeron *eph = (GC_Ephemeron *)p;

  if (eph->val) {
    eph->next = gc->ephemerons;
    gc->ephemerons = eph;
  }

  return gcBYTES_TO_WORDS(sizeof(GC_Ephemeron));
}
Esempio n. 14
0
static int mark_weak_array(void *p, struct NewGC *gc)
{
  GC_Weak_Array *a = (GC_Weak_Array *)p;

  gcMARK2(a->replace_val, gc);

  if (gc->doing_memory_accounting) {
    /* skip */
  } else if (gc->inc_gen1) {
    /* inc_next field is at the end of the `data` array: */
    a->data[a->count] = gc->inc_weak_arrays;
    gc->inc_weak_arrays = a;
  } else if (gc->during_backpointer) {
    if (!gc->gc_full
        || (gc->started_incremental
            /* `a` must have been marked and must be in the old
               generation, or we wouldn't get here; `a` may have been
               fully processed in incremental mode, though */
            && (a->data[a->count] == gc->weak_incremental_done))) {
      /* Keep backpointered weak arrays separate, because we
         should not merge them to the incremental list
         in incremental mode. */
      a->next = gc->bp_weak_arrays;
      gc->bp_weak_arrays = a;
    }
  } else {
    a->next = gc->weak_arrays;
    gc->weak_arrays = a;
    if (gc->gc_full)
      a->data[a->count] = NULL; /* ensure not a future weak_incremental_done */
  }

#if CHECKS
  /* For now, weak arrays only used for symbols, keywords, and falses: */
  {
    void **data;
    int i;
    data = a->data;
    for (i = a->count; i--; ) {
      if (data[i] 
	  && (*(short *)(data[i]) != 48)
	  && (*(short *)(data[i]) != 49)
	  && (*(short *)(data[i]) != 58)) {
	CRASH(1);
      }
    }
  }
#endif

  return gcBYTES_TO_WORDS(sizeof(GC_Weak_Array) 
			  + ((a->count - 1 + 1) * sizeof(void *)));
}
Esempio n. 15
0
static int mark_weak_box(void *p)
{
  GC_Weak_Box *wb = (GC_Weak_Box *)p;
    
  gcMARK(wb->secondary_erase);

  if (wb->val) {
    wb->next = weak_boxes;
    weak_boxes = wb;
  }

  return gcBYTES_TO_WORDS(sizeof(GC_Weak_Box));
}
Esempio n. 16
0
static int BTC_ephemeron_mark(void *p, struct NewGC *gc)
{
  if (gc->doing_memory_accounting) {

    GC_Ephemeron *eph = (GC_Ephemeron *)p;

    gcMARK2(eph->key, gc);
    gcMARK2(eph->val, gc);

    return gcBYTES_TO_WORDS(sizeof(GC_Ephemeron));
  }
  return mark_ephemeron(p, gc);
}
Esempio n. 17
0
static int mark_weak_box(void *p, struct NewGC *gc)
{
  GC_Weak_Box *wb = (GC_Weak_Box *)p;
    
  gcMARK2(wb->secondary_erase, gc);

  if (wb->val) {
    wb->next = gc->weak_boxes[wb->is_late];
    gc->weak_boxes[wb->is_late] = wb;
  }

  return gcBYTES_TO_WORDS(sizeof(GC_Weak_Box));
}
Esempio n. 18
0
inline static void BTC_memory_account_mark(NewGC *gc, mpage *page, void *ptr, int is_a_master_page)
{
  GCDEBUG((DEBUGOUTF, "BTC_memory_account_mark: %p/%p\n", page, ptr));

  /* In the case of is_a_master_page, whether this place is charged is
     a little random: there's no guarantee that the btc_mark values
     are in sync, and there are races among places. Approximations are
     ok for accounting, though, as long as the probably for completely
     wrong accounting is very low.

     At the same time, we need to synchronize enough so that two
     places with different new_btc_mark values don't send each other
     into infinite loops (with the btc_mark value bouncing back and
     forth) or overcounting. We synchronize enough by having a single
     new_btc_mark value for master pages, and we stall if the value
     isn't what this place wants. */

  if (is_a_master_page)
    check_master_btc_mark(gc, page);

  if(page->size_class) {
    if(page->size_class > 1) {
      /* big page */
      objhead *info = BIG_PAGE_TO_OBJHEAD(page);
      
      if(info->btc_mark == gc->old_btc_mark) {
        info->btc_mark = gc->new_btc_mark;
        account_memory(gc, gc->current_mark_owner, gcBYTES_TO_WORDS(page->size), is_a_master_page);
        push_ptr(gc, TAG_AS_BIG_PAGE_PTR(ptr));
      }
    } else {
      /* medium page */
      objhead *info = MED_OBJHEAD(ptr, page->size);

      if(info->btc_mark == gc->old_btc_mark) {
        info->btc_mark = gc->new_btc_mark;
        account_memory(gc, gc->current_mark_owner, info->size, is_a_master_page);
        ptr = OBJHEAD_TO_OBJPTR(info);
        push_ptr(gc, ptr);
      }
    }
  } else {
    objhead *info = OBJPTR_TO_OBJHEAD(ptr);

    if(info->btc_mark == gc->old_btc_mark) {
      info->btc_mark = gc->new_btc_mark;
      account_memory(gc, gc->current_mark_owner, info->size, 0);
      push_ptr(gc, ptr);
    }
  }
}
Esempio n. 19
0
static int fixup_weak_array(void *p, struct NewGC *gc)
{
  GC_Weak_Array *a = (GC_Weak_Array *)p;
  int i;
  void **data;

  gcFIXUP2(a->replace_val, gc);

  data = a->data;
  for (i = a->count; i--; ) {
    if (data[i])
      gcFIXUP2(data[i], gc);
  }

  return gcBYTES_TO_WORDS(sizeof(GC_Weak_Array) 
			  + ((a->count - 1) * sizeof(void *)));
}
Esempio n. 20
0
inline static void BTC_memory_account_mark(NewGC *gc, mpage *page, void *ptr, int is_a_master_page)
{
  GCDEBUG((DEBUGOUTF, "BTC_memory_account_mark: %p/%p\n", page, ptr));

  /* In the case of is_a_master_page, whether this place is charged is
     a little random: there's no guarantee that the btc_mark values are
     in sync, and there are races among places. Approximations are ok for
     accounting, though, as long as the probably for completely wrong
     accounting is very low. */

  if(page->size_class) {
    if(page->size_class > 1) {
      /* big page */
      objhead *info = BIG_PAGE_TO_OBJHEAD(page);
      
      if(info->btc_mark == gc->old_btc_mark) {
        info->btc_mark = gc->new_btc_mark;
        account_memory(gc, gc->current_mark_owner, gcBYTES_TO_WORDS(page->size), is_a_master_page);
        push_ptr(gc, TAG_AS_BIG_PAGE_PTR(ptr));
      }
    } else {
      /* medium page */
      objhead *info = MED_OBJHEAD(ptr, page->size);

      if(info->btc_mark == gc->old_btc_mark) {
        info->btc_mark = gc->new_btc_mark;
        account_memory(gc, gc->current_mark_owner, info->size, is_a_master_page);
        ptr = OBJHEAD_TO_OBJPTR(info);
        push_ptr(gc, ptr);
      }
    }
  } else {
    objhead *info = OBJPTR_TO_OBJHEAD(ptr);

    if(info->btc_mark == gc->old_btc_mark) {
      info->btc_mark = gc->new_btc_mark;
      account_memory(gc, gc->current_mark_owner, info->size, 0);
      push_ptr(gc, ptr);
    }
  }
}
Esempio n. 21
0
static int mark_weak_box(void *p, struct NewGC *gc)
{
  GC_Weak_Box *wb = (GC_Weak_Box *)p;

  gcMARK2(wb->secondary_erase, gc);

  if (gc->doing_memory_accounting) {
    /* skip */
  } else if (gc->inc_gen1) {
    check_weak_box_not_already_in_inc_chain(wb, gc->inc_weak_boxes[wb->is_late]);
    wb->inc_next = gc->inc_weak_boxes[wb->is_late];
    gc->inc_weak_boxes[wb->is_late] = wb;
  } else if (gc->during_backpointer) {
    if ((!gc->gc_full
         || (gc->started_incremental
             /* see note with `gc->weak_incremental_done` for weak arrays */
             && (wb->inc_next == gc->weak_incremental_done)
             && wb->val))
        && (wb->val || gc->started_incremental)) {
      /* Keep backpointered weak arrays separate, because we
         should not merge them to the incremental list
         in incremental mode. */
      check_weak_box_not_already_in_chain(wb, gc->bp_weak_boxes[wb->is_late]);
      check_weak_box_not_already_in_chain(wb, gc->weak_boxes[wb->is_late]);
      wb->next = gc->bp_weak_boxes[wb->is_late];
      gc->bp_weak_boxes[wb->is_late] = wb;
    }
  } else if (wb->val || gc->started_incremental) {
    check_weak_box_not_already_in_chain(wb, gc->weak_boxes[wb->is_late]);
    check_weak_box_not_already_in_chain(wb, gc->bp_weak_boxes[wb->is_late]);
    wb->next = gc->weak_boxes[wb->is_late];
    gc->weak_boxes[wb->is_late] = wb;
    if (gc->gc_full)
      wb->inc_next = NULL; /* ensure not a future weak_incremental_done */
  }

  return gcBYTES_TO_WORDS(sizeof(GC_Weak_Box));
}
Esempio n. 22
0
static int size_weak_box(void *p, struct NewGC *gc)
{
  return gcBYTES_TO_WORDS(sizeof(GC_Weak_Box));
}
Esempio n. 23
0
static int size_ephemeron(void *p, struct NewGC *gc)
{
  return gcBYTES_TO_WORDS(sizeof(GC_Ephemeron));
}
Esempio n. 24
0
static int size_weak_box(void *p)
{
  return gcBYTES_TO_WORDS(sizeof(GC_Weak_Box));
}
Esempio n. 25
0
static int size_ephemeron(void *p)
{
  return gcBYTES_TO_WORDS(sizeof(GC_Ephemeron));
}
Esempio n. 26
0
static void BTC_do_accounting(NewGC *gc)
{
  const int table_size = gc->owner_table_size;
  OTEntry **owner_table = gc->owner_table;

  if(gc->really_doing_accounting) {
    Scheme_Custodian *cur = owner_table[current_owner(gc, NULL)]->originator, *last, *parent;
    Scheme_Custodian_Reference *box = cur->global_next;
    int i;

    GCDEBUG((DEBUGOUTF, "\nBEGINNING MEMORY ACCOUNTING\n"));
    gc->doing_memory_accounting = 1;
    gc->in_unsafe_allocation_mode = 1;
    gc->unsafe_allocation_abort = btc_overmem_abort;
    gc->master_page_btc_mark_checked = 0;

    /* clear the memory use numbers out */
    for(i = 1; i < table_size; i++)
      if(owner_table[i]) {
        owner_table[i]->memory_use = 0;
#ifdef MZ_USE_PLACES
        if (MASTERGC && MASTERGC->major_places_gc)
          owner_table[i]->master_memory_use = 0;
#endif
      }
    
    /* start with root: */
    while (cur->parent && SCHEME_PTR1_VAL(cur->parent)) {
      cur = SCHEME_PTR1_VAL(cur->parent);
    }

    /* walk forward for the order we want (blame parents instead of children) */
    last = cur;
    while(cur) {
      int owner = custodian_to_owner_set(gc, cur);
      uintptr_t save_count = gc->phantom_count;

      gc->phantom_count = 0;

      gc->current_mark_owner = owner;
      GCDEBUG((DEBUGOUTF,"MARKING THREADS OF OWNER %i (CUST %p)\n", owner, cur));
      gc->kill_propagation_loop = 0;
      mark_threads(gc, owner);
      mark_cust_boxes(gc, cur);
      GCDEBUG((DEBUGOUTF, "Propagating accounting marks\n"));
      propagate_accounting_marks(gc);

      last = cur;
      box = cur->global_next; cur = box ? SCHEME_PTR1_VAL(box) : NULL;

      owner_table = gc->owner_table;
      owner_table[owner]->memory_use = add_no_overflow(owner_table[owner]->memory_use, 
                                                       gcBYTES_TO_WORDS(gc->phantom_count));
      gc->phantom_count = save_count;
    }

    release_master_btc_mark(gc);

    /* walk backward folding totals int parent */
    cur = last;
    while (cur) {
      int owner = custodian_to_owner_set(gc, cur);
      
      box = cur->parent; parent = box ? SCHEME_PTR1_VAL(box) : NULL;
      if (parent) {
        int powner = custodian_to_owner_set(gc, parent);

        owner_table = gc->owner_table;
        owner_table[powner]->memory_use = add_no_overflow(owner_table[powner]->memory_use,
                                                          owner_table[owner]->memory_use);
        owner_table[powner]->master_memory_use += owner_table[owner]->master_memory_use;
      }

      box = cur->global_prev; cur = box ? SCHEME_PTR1_VAL(box) : NULL;
    }

    gc->in_unsafe_allocation_mode = 0;
    gc->doing_memory_accounting = 0;
    gc->old_btc_mark = gc->new_btc_mark;
    gc->new_btc_mark = !gc->new_btc_mark;
  }

  clear_stack_pages(gc);
}