#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