corda/src/zone.h

152 lines
3.3 KiB
C
Raw Normal View History

/* Copyright (c) 2008-2011, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
2007-12-11 00:48:09 +00:00
#ifndef ZONE_H
#define ZONE_H
#include "system.h"
#include "allocator.h"
2007-12-11 00:48:09 +00:00
namespace vm {
class Zone: public Allocator {
2007-12-11 00:48:09 +00:00
public:
class Segment {
public:
Segment(Segment* next, unsigned size):
next(next), size(size), position(0)
{ }
2007-12-11 00:48:09 +00:00
Segment* next;
uintptr_t size;
uintptr_t position;
2007-12-11 00:48:09 +00:00
uint8_t data[0];
};
2008-04-13 18:15:04 +00:00
Zone(System* s, Allocator* allocator, unsigned minimumFootprint):
2007-12-11 00:48:09 +00:00
s(s),
allocator(allocator),
2007-12-11 00:48:09 +00:00
segment(0),
minimumFootprint(minimumFootprint < sizeof(Segment) ? 0 :
minimumFootprint - sizeof(Segment))
2007-12-11 00:48:09 +00:00
{ }
~Zone() {
dispose();
}
void dispose() {
for (Segment* seg = segment, *next; seg; seg = next) {
next = seg->next;
2008-04-13 18:15:04 +00:00
allocator->free(seg, sizeof(Segment) + seg->size);
2007-12-11 00:48:09 +00:00
}
segment = 0;
2007-12-11 00:48:09 +00:00
}
static unsigned padToPage(unsigned size) {
return (size + (LikelyPageSizeInBytes - 1))
& ~(LikelyPageSizeInBytes - 1);
}
bool tryEnsure(unsigned space) {
if (segment == 0 or segment->position + space > segment->size) {
unsigned size = padToPage
(max
(space, max
(minimumFootprint, segment == 0 ? 0 : segment->size * 2))
+ sizeof(Segment));
2008-04-13 18:15:04 +00:00
void* p = allocator->tryAllocate(size);
if (p == 0) {
size = padToPage(space + sizeof(Segment));
p = allocator->tryAllocate(size);
if (p == 0) {
return false;
}
}
segment = new (p) Segment(segment, size - sizeof(Segment));
2007-12-11 00:48:09 +00:00
}
return true;
2007-12-11 00:48:09 +00:00
}
void ensure(unsigned space) {
if (segment == 0 or segment->position + space > segment->size) {
unsigned size = padToPage(space + sizeof(Segment));
segment = new (allocator->allocate(size))
Segment(segment, size - sizeof(Segment));
}
}
2008-04-13 18:15:04 +00:00
virtual void* tryAllocate(unsigned size) {
2007-12-11 00:48:09 +00:00
size = pad(size);
if (tryEnsure(size)) {
void* r = segment->data + segment->position;
segment->position += size;
return r;
} else {
return 0;
}
}
2008-04-13 18:15:04 +00:00
virtual void* allocate(unsigned size) {
size = pad(size);
2008-04-13 18:15:04 +00:00
void* p = tryAllocate(size);
if (p) {
return p;
} else {
ensure(size);
void* r = segment->data + segment->position;
segment->position += size;
return r;
}
}
void* peek(unsigned size) {
size = pad(size);
Segment* s = segment;
while (s->position < size) {
size -= s->position;
s = s->next;
}
return s->data + (s->position - size);
}
void pop(unsigned size) {
size = pad(size);
Segment* s = segment;
while (s->position < size) {
size -= s->position;
Segment* next = s->next;
allocator->free(s, sizeof(Segment) + s->size);
s = next;
}
s->position -= size;
segment = s;
}
2008-04-13 18:15:04 +00:00
virtual void free(const void*, unsigned) {
// not supported
abort(s);
2007-12-11 00:48:09 +00:00
}
System* s;
Allocator* allocator;
void* context;
2007-12-11 00:48:09 +00:00
Segment* segment;
unsigned minimumFootprint;
2007-12-11 00:48:09 +00:00
};
} // namespace vm
#endif//ZONE_H