Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
heaps, types: added LIFO-style memory allocation, primarily for conti…
…nuations

  When using LIFO-style memory allocation, objects may be manually
    deallocated in the reverse order of allocation.
  Object deallocation may silently fail (no error conditions) if
    objects are deallocated in the wrong order.
  However, objects allocated on the LIFO-style memory are still
    subject to garbage collection; if they survive the collection,
    they are no longer in the LIFO space (and deallocation will
    silently fail), but they will be considered as part of the
    "main" heap.
  • Loading branch information
AmkG committed Aug 5, 2008
1 parent ade1ed9 commit d4ac6b6
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 16 deletions.
65 changes: 63 additions & 2 deletions inc/heaps.hpp
Expand Up @@ -35,9 +35,37 @@ class Semispace{
friend class Heap;
};

/*last-in-first-out allocation semispace*/
class LifoSemispace {
private:
void* mem;
void* allocpt;
void* end;
size_t prevalloc;
public:
LifoSemispace(size_t sz);
~LifoSemispace();
void* alloc(size_t sz);
void dealloc(void*); // used only in a constructor-fail delete
void normal_dealloc(Generic*);
bool can_fit(size_t) const;
size_t size(void) const {
return (size_t) (((char*) end) - ((char*) mem));
}
size_t used(void) const {
return (size_t) (((char*) end) - ((char*) allocpt));
}

/*no need to clone LIFO semispaces: they never get passed around*/
friend class Heap;
};

class LifoHeap;

class Heap{
private:
boost::scoped_ptr<Semispace> s;
boost::scoped_ptr<LifoSemispace> ls;
bool tight;
protected:
/*conceptually these should be scoped_ptr's, but
Expand All @@ -49,15 +77,42 @@ class Heap{
std::vector<boost::shared_ptr<Semispace> > other_spaces;
virtual void get_root_set(std::stack<Generic**>&) =0;
size_t get_total_heap_size(void) const;
void GC(size_t);
void GC(size_t,bool from_lifo=0);
public:
void* alloc(size_t);
void dealloc(void*);
boost::shared_ptr<Semispace> to_new_semispace(Generic*&) const;
Heap(void) : s(new Semispace(64)), tight(0) {};
Heap(void);
virtual ~Heap(){};

void* lifo_alloc(size_t);
void lifo_dealloc(void*);
void lifo_normal_dealloc(Generic*);

LifoHeap lifo(void);

};

class LifoHeap {
private:
Heap* hp;
public:
LifoHeap(Heap* nhp) : hp(nhp) {}

void* alloc(size_t sz){return hp->lifo_alloc(sz);}
void dealloc(void* pt){return hp->lifo_dealloc(pt);}
void normal_dealloc(Generic* gp){return hp->lifo_normal_dealloc(gp);}
};

inline Heap::Heap(void)
: s(new Semispace(64)),
tight(0),
ls(new LifoSemispace(64)) {}

inline LifoHeap Heap::lifo(void){
return LifoHeap(this);
}

inline void* operator new(size_t n, Semispace& sp){
return sp.alloc(n);
}
Expand All @@ -78,6 +133,12 @@ inline void operator delete(void* p, Heap& hp){
/*necessary for proper cleanup in case the ctor throws*/
hp.dealloc(p);
}
inline void* operator new(size_t n, LifoHeap hp){
return hp.alloc(n);
}
inline void operator delete(void* p, LifoHeap hp){
hp.dealloc(p);
}

#endif //HEAPS_H

88 changes: 81 additions & 7 deletions src/heaps.cpp
Expand Up @@ -4,7 +4,7 @@
#include<cstring>

/*-----------------------------------------------------------------------------
Semispaces
Semispace
-----------------------------------------------------------------------------*/

static ptrdiff_t moveallreferences(void* mem, void* allocpt, void* nmem){
Expand Down Expand Up @@ -125,18 +125,72 @@ std::pair<boost::shared_ptr<Semispace>, Generic* >
}

/*-----------------------------------------------------------------------------
Heaps
LifoSemispace
-----------------------------------------------------------------------------*/

LifoSemispace::LifoSemispace(size_t sz) {
mem = 0;
try{
mem = malloc(sz);
if(mem == NULL) throw std::bad_alloc();
allocpt = end = ((char*) mem) + sz;
prevalloc = 0;
}catch(...){
if(mem) free(mem);
throw;
}
}

LifoSemispace::~LifoSemispace(){
while(allocpt < end){
normal_dealloc((Generic*) allocpt);
}
free(mem);
}

void* LifoSemispace::alloc(size_t sz){
/*assertion; shouldn't trigger*/
if(!can_fit(sz)) throw std::bad_alloc();
allocpt = ((char*)allocpt) - sz;
prevalloc = sz;
return allocpt;
}

/*this should only get called on a failed construction*/
void LifoSemispace::dealloc(void* pt){
if(pt != allocpt) throw std::bad_alloc();
allocpt = ((char*)allocpt) + prevalloc;
prevalloc = 0;
}

/*this should get called after the object is fully constructed*/
void LifoSemispace::normal_dealloc(Generic* pt){
if(pt != allocpt) return; // do nothing if we can't trivially pop off
/*get the size of the object*/
size_t sz = pt->get_size();
/*destroy*/
pt->~Generic();
allocpt = ((char*)allocpt) + sz;
}

bool LifoSemispace::can_fit(size_t sz) const {
return (((char*)allocpt) - sz) >= (char*)mem;
}

/*-----------------------------------------------------------------------------
Heap
-----------------------------------------------------------------------------*/

/*preconditions:
other_spaces must be locked!
*/
size_t Heap::get_total_heap_size(void) const{
size_t sz = s->size();
size_t sz = s->used();
std::vector<boost::shared_ptr<Semispace> >::const_iterator i;
for(i = other_spaces.begin(); i != other_spaces.end(); ++i){
sz += (*i)->size();
sz += (*i)->used();
}
sz += ls->used();
return sz;
}

Expand All @@ -161,27 +215,34 @@ static void copy_set(std::stack<Generic**>& tocopy,
}

/*explicit recursion copy*/
void Heap::GC(size_t insurance){
void Heap::GC(size_t insurance, bool from_lifo){
/*insert mutex locking of other_spaces here*/

size_t sz = get_total_heap_size() + insurance;
/*calculate sizes*/
size_t sz = get_total_heap_size();
size_t lsz = ls->size();
if(from_lifo) lsz += insurance * 2;
else sz += insurance;
if(tight){ sz = sz * 2;}

boost::scoped_ptr<Semispace> ns(new Semispace(sz));
boost::scoped_ptr<LifoSemispace> nls(new LifoSemispace(lsz));
ToPointerLock toptrs;
std::stack<Generic**> tocopy;

get_root_set(tocopy);
copy_set(tocopy, toptrs, *ns);

s.swap(ns); //shouldn't throw
ls.swap(nls);
/*successful GC, don't bother clearing*/
toptrs.good();
other_spaces.clear();
ns.reset();

/*determine if resizing necessary*/
size_t used = s->used() + insurance;
size_t used = s->used();
if(!from_lifo) used += insurance;
tight = 0;
if(used <= sz / 4){
s->resize(sz / 2);
Expand All @@ -203,6 +264,19 @@ void Heap::dealloc(void* check){
s->dealloc(check);
}

void* Heap::lifo_alloc(size_t sz){
if(!ls->can_fit(sz)){
GC(sz, 1);
}
return ls->alloc(sz);
}
void Heap::lifo_dealloc(void* check){
ls->dealloc(check);
}
void Heap::lifo_normal_dealloc(Generic* gp){
ls->normal_dealloc(gp);
}

boost::shared_ptr<Semispace> Heap::to_new_semispace(Generic*& gp) const {
/*Determine the size*/
ToPointerLock toptrs;
Expand Down
11 changes: 4 additions & 7 deletions src/types.cpp
Expand Up @@ -231,9 +231,9 @@ class ClosureVector : public C {
/*constructs a Closure of the given size with the given Executor
The constructed Closure may be any of the above implementations.
*/
template<typename C>
template<typename C, typename A>
static C* NewClosureImpl(
Heap& hp, boost::shared_ptr<Executor> c, size_t sz) {
A hp, boost::shared_ptr<Executor> c, size_t sz) {
switch(sz){
/*Use statically-determined sizes as much as possible*/
case 0: return new(hp) EmptyClosure<C>(c);
Expand All @@ -253,16 +253,13 @@ Closure* NewClosure(Heap& hp, Executor* c, size_t sz) {
return NewClosure(hp, boost::shared_ptr<Executor>(c), sz);
}
Closure* NewClosure(Heap& hp, boost::shared_ptr<Executor> c, size_t sz) {
return NewClosureImpl<Closure>(hp, c, sz);
return NewClosureImpl<Closure,Heap&>(hp, c, sz);
}
/*TODO: make these allocate in the LIFO allocation structure, when that
is implemented
*/
KClosure* NewKClosure(Heap& hp, Executor* c, size_t sz) {
return NewKClosure(hp, boost::shared_ptr<Executor>(c), sz);
}
KClosure* NewKClosure(Heap& hp, boost::shared_ptr<Executor> c, size_t sz) {
return NewClosureImpl<KClosure>(hp, c, sz);
return NewClosureImpl<KClosure,LifoHeap>(hp.lifo(), c, sz);
}

/*DEBUG CODE*/
Expand Down

0 comments on commit d4ac6b6

Please sign in to comment.