Docs GODI Archive
Projects Blog Link DB

Search GODI:


More options
File lib/felix/rtl/flx_collector.cpp GODI Package apps-felix
 
   flx_collector.cpp  
#line 497 "lpsrc/flx_gc.ipk"
#include <cstdlib>
#include <map>
#include <limits.h>
#include <cassert>
#include <cstdio>
#include <cstddef>
#include "flx_rtl_config.hpp"
#include "flx_collector.hpp"
namespace flx {
namespace gc {
namespace collector {

static int mcount FLX_UNUSED = 0;
#ifdef HAVE_GXX_X86
register void *sp __asm__("esp");
#else
static void *sp = 0;
#endif

void *low_sp = 0;
void *hi_sp = 0;

void *malloc_free::allocate(std::size_t amt)
{
  void *p = malloc(amt);
  if(debug)fprintf(stderr,"Malloc %p\n",p);
  //++mcount;
  //void *x = sp;
  //if (low_sp == NULL) low_sp = x,hi_sp = x;
  //else {
  //  if (x < low_sp) low_sp = x;
  //  if (x > hi_sp) hi_sp = x;
  //}
  //if(mcount%100==0)printf("malloc %p, count=%d,stack size = %ld\n",p,mcount,(char*)hi_sp - (char*)low_sp);
  if(p)return p;
  else {
    fprintf(stderr,"Felix: Malloc out of memory, blk=%ld\n",long(amt));
    abort();
  }
}

void malloc_free::deallocate(void *p, std::size_t)
{
  //printf("free %p\n",p);
  if(debug)fprintf(stderr,"Free %p\n",p);
  free(p);
}

unsigned long flx_collector_t::get_allocation_count()const
{
  return allocation_count;
}

unsigned long flx_collector_t::get_root_count()const
{
  return root_count;
}

unsigned long flx_collector_t::get_allocation_amt()const
{
  return allocation_amt;
}


flx_collector_t::flx_collector_t(allocator_t *a) :
  collecting(false),
  allocation_count(0),
  root_count(0),
  allocation_amt(0),
  first(0),
  to_delete(0),
  parity(false),
  allocator(a)
{}


void * flx_collector_t::allocate(gc_shape_t *shape, unsigned long nobj)
{
  // calculate how much memory to request
  std::size_t amt = nobj * shape->amt + FRAMESIZE;

  // allocate a block
  frame_t *fp = (frame_t*)allocator->allocate(amt);
  assert(fp); // Got some memory!

  // initialise the shape, garbage flag, and refcount
  fp->shape = shape;
  fp->garbage = parity;
  fp->finalised = false;
  fp->n_objects = nobj;
  fp->collector = this;

  // link the frame into the collectors list
  fp->prev = 0;
  fp->next = first;
  if(first) first->prev = fp;
  first = fp;

  // update statistics
  allocation_count++;
  allocation_amt += amt;

  // return client memory pointer
  return FRAME_TO_CLIENT(fp);
}

void flx_collector_t::deallocate(frame_t *fp)
{
  unlink(fp);
  dispose(fp);
}

void flx_collector_t::unlink(frame_t *fp)
{

  // check we have a pointer to an object
  assert(fp);

  // flag the object as finalised, even before
  // actually calling the finaliser, to
  // prevent recursion via destroy
  fp->finalised = true;

  // call the finaliser if there is one
  void (*finaliser)(collector_t*, void*) = fp->shape->finaliser;
  if (finaliser)
  {
    void *cp = FRAME_TO_CLIENT(fp);
    (*finaliser)(this,cp);
  }
  // unlink the frame from the collectors list
  if(fp->prev)
    fp->prev->next = fp->next;
  else {
    assert(first==fp);
    first=fp->next;
  }
  if(fp->next)
    fp->next->prev = fp->prev;
}

void flx_collector_t::post_delete(frame_t *fp)
{
  assert(collecting);
  // link into list of objects to delete
  // this list uses the prev pointer!
  fp->prev = to_delete;
  to_delete = fp;
}

void flx_collector_t::dispose(frame_t *fp)
{
  if(collecting) post_delete(fp);
  else delete_frame(fp);
}

void flx_collector_t::delete_frame(frame_t *fp)
{
  // update statistics
  allocation_count--;
  std::size_t size = fp->shape->amt + FRAMESIZE;
  allocation_amt -= size;

  // deallocate the storage
  allocator->deallocate(fp, size);
}

unsigned long flx_collector_t::reap ()
{
  unsigned long count = 0;
  while(to_delete)
  {
    frame_t *next = to_delete-> prev;
    delete_frame(to_delete);
    to_delete = next;
    ++count;
  }
  return count;
}


unsigned long flx_collector_t::sweep()
{
  if(debug)fprintf(stderr,"Collector: Sweep\n");
  collecting=true;
  frame_t *current = first;
  while(current)
  {
    if(current->garbage == parity)
    {
      if(debug)fprintf(stderr,"Garbage %p=%s\n",current,current->shape->cname);
      unlink(current);
      post_delete(current);
    }
    current = current->next;
  }
  parity = !parity;
  collecting = false;
  return reap();
}

void flx_collector_t::add_root(void *memory)
{
  if(!memory)
  {
    fprintf(stderr, "GC ERROR: ADD NULL ROOT\n");
    abort();
  }
  frame_t *p =  CLIENT_TO_FRAME(memory);
  rootmap_t::iterator iter = roots.find(p);
  if(iter == roots.end())
  {
    std::pair<frame_t *const, unsigned long> entry(p,1UL);
    roots.insert (entry);
    root_count++;
  }
  else
    ++(*iter).second;
}

void flx_collector_t::remove_root(void *memory)
{
  frame_t *p =  CLIENT_TO_FRAME(memory);
  rootmap_t::iterator iter = roots.find(p);
  if(iter == roots.end())
  {
    fprintf(stderr, "GC ERROR: REMOVE ROOT WHICH IS NOT ROOT\n");
    abort();
  }
  if((*iter).second == 1UL)
  {
    roots.erase(iter);
    root_count--;
  }
  else
    --(*iter).second;
}

void flx_collector_t::scan_object(frame_t *frame)
{
  if(debug)fprintf(stderr,"Scanning %p\n",frame);
  if(debug)fprintf(stderr,"Scanning [valid] %p=%s\n",frame,frame->shape->cname);
  if(frame->garbage == parity)
  {
    if(debug){
      fprintf(stderr,"Reachable %p\n",frame);
      gc_shape_t * shape = frame->shape;
      fprintf(stderr,"Reachable [valid] %p=%s\n",frame,shape->cname);
      for(unsigned int i=0; i<shape->n_offsets; ++i)
      {
        unsigned long offset = shape->offsets[i];
        unsigned char *p = (unsigned char*)FRAME_TO_CLIENT(frame);
        void *x = *(void**)(p+offset);
        if(x) {
          bool valid = check_client_pointer(x);
          fprintf(stderr," offset: 0x%04lx %p->[%p-0x%x] %s\n",
            offset,p+offset,x,FRAMESIZE,
            valid?"[valid]":"INVALID"
          );
          if(!valid) abort();
        }
        else
          fprintf(stderr," offset: 0x%04lx %p->[%p] NULL\n",
            offset,p+offset,x);
      }
    }
    frame->garbage = !parity; // reachable!
    gc_shape_t *shape = frame->shape;
    unsigned long n_objects = frame->n_objects * shape->count;
    std::size_t obj_size = shape->amt;
    std::size_t n_offsets = shape->n_offsets;
    std::size_t *offsets = shape->offsets;
    unsigned char *p = (unsigned char*)FRAME_TO_CLIENT(frame);

    for(unsigned long j=0; j<n_objects; ++j)
    {
      for(unsigned int i=0; i<n_offsets; ++i)
      {
        void **q = (void**)(void*)(p + offsets[i]);
        if(*q)
          scan_object(CLIENT_TO_FRAME(*q));
      }
      p+=obj_size;
    }
  }
}

void flx_collector_t::mark()
{
  if(debug)fprintf(stderr,"Collector: Running mark\n");
  assert (root_count == roots.size());

  rootmap_t::iterator const end = roots.end();
  for(
    rootmap_t::iterator i = roots.begin();
    i != end;
    ++i
  )
    scan_object((*i).first);
}

unsigned long flx_collector_t::collect()
{
  if(debug)fprintf(stderr,"Running collector\n");
  mark();
  return sweep();
}

void flx_collector_t::check()
{
 // not implemented: should scan all objects,
 // and check total memory is as expected
 // can also check back links, statistics,
 // and parity
}

bool flx_collector_t::check_frame_pointer(frame_t *p)
{
  frame_t *current = first;
  while(current)
  {
    if(current == p) return true;
    current = current->next;
  }
  return false;
}

bool flx_collector_t::check_client_pointer(void *p)
{
  return p?check_frame_pointer (CLIENT_TO_FRAME(p)):true;
}

flx_collector_t::~flx_collector_t()
{
  //THIS IS VERY DANGEROUS! What if don't want to collect
  //the garbage for efficiency reasons???
  //
  // ELIDED .. already caused a bug!
  //
  //roots.clear();
  //root_count = 0;
  //sweep();
}

}}} // end namespaces



This web site is published by Informatikbüro Gerd Stolpmann
Powered by Caml