2011-07-13 14:25:21 +00:00
|
|
|
/* Copyright (c) 2008-2011, Avian Contributors
|
2008-02-19 18:06:52 +00:00
|
|
|
|
|
|
|
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"
|
2008-01-10 01:20:36 +00:00
|
|
|
#include "allocator.h"
|
2007-12-11 00:48:09 +00:00
|
|
|
|
|
|
|
namespace vm {
|
|
|
|
|
2008-01-10 01:20:36 +00:00
|
|
|
class Zone: public Allocator {
|
2007-12-11 00:48:09 +00:00
|
|
|
public:
|
|
|
|
class Segment {
|
|
|
|
public:
|
2012-10-13 15:46:12 +00:00
|
|
|
Segment(Segment* next, unsigned size):
|
|
|
|
next(next), size(size), position(0)
|
|
|
|
{ }
|
2007-12-11 00:48:09 +00:00
|
|
|
|
|
|
|
Segment* next;
|
2008-01-10 01:20:36 +00:00
|
|
|
uintptr_t size;
|
2012-10-13 15:46:12 +00:00
|
|
|
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),
|
2008-01-13 22:05:08 +00:00
|
|
|
allocator(allocator),
|
2007-12-11 00:48:09 +00:00
|
|
|
segment(0),
|
2008-01-10 01:20:36 +00:00
|
|
|
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
|
|
|
}
|
2011-03-15 23:52:02 +00:00
|
|
|
|
|
|
|
segment = 0;
|
2007-12-11 00:48:09 +00:00
|
|
|
}
|
|
|
|
|
2011-03-26 00:14:34 +00:00
|
|
|
static unsigned padToPage(unsigned size) {
|
|
|
|
return (size + (LikelyPageSizeInBytes - 1))
|
|
|
|
& ~(LikelyPageSizeInBytes - 1);
|
|
|
|
}
|
2008-01-10 01:20:36 +00:00
|
|
|
|
2011-03-26 00:14:34 +00:00
|
|
|
bool tryEnsure(unsigned space) {
|
2012-10-13 15:46:12 +00:00
|
|
|
if (segment == 0 or segment->position + space > segment->size) {
|
2011-03-26 00:14:34 +00:00
|
|
|
unsigned size = padToPage
|
|
|
|
(max
|
|
|
|
(space, max
|
|
|
|
(minimumFootprint, segment == 0 ? 0 : segment->size * 2))
|
|
|
|
+ sizeof(Segment));
|
2008-01-10 01:20:36 +00:00
|
|
|
|
2008-04-13 18:15:04 +00:00
|
|
|
void* p = allocator->tryAllocate(size);
|
2008-01-10 01:20:36 +00:00
|
|
|
if (p == 0) {
|
2011-03-26 00:14:34 +00:00
|
|
|
size = padToPage(space + sizeof(Segment));
|
|
|
|
p = allocator->tryAllocate(size);
|
2008-01-10 01:20:36 +00:00
|
|
|
if (p == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
segment = new (p) Segment(segment, size - sizeof(Segment));
|
2007-12-11 00:48:09 +00:00
|
|
|
}
|
2008-01-10 01:20:36 +00:00
|
|
|
return true;
|
2007-12-11 00:48:09 +00:00
|
|
|
}
|
|
|
|
|
2011-03-26 00:14:34 +00:00
|
|
|
void ensure(unsigned space) {
|
2012-10-13 15:46:12 +00:00
|
|
|
if (segment == 0 or segment->position + space > segment->size) {
|
2011-03-26 00:14:34 +00:00
|
|
|
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);
|
2011-03-26 00:14:34 +00:00
|
|
|
if (tryEnsure(size)) {
|
2012-10-13 15:46:12 +00:00
|
|
|
void* r = segment->data + segment->position;
|
|
|
|
segment->position += size;
|
2008-01-10 01:20:36 +00:00
|
|
|
return r;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-13 18:15:04 +00:00
|
|
|
virtual void* allocate(unsigned size) {
|
2012-10-13 15:46:12 +00:00
|
|
|
size = pad(size);
|
2008-04-13 18:15:04 +00:00
|
|
|
void* p = tryAllocate(size);
|
2011-03-26 00:14:34 +00:00
|
|
|
if (p) {
|
|
|
|
return p;
|
|
|
|
} else {
|
|
|
|
ensure(size);
|
2012-10-13 15:46:12 +00:00
|
|
|
void* r = segment->data + segment->position;
|
|
|
|
segment->position += size;
|
2011-03-26 00:14:34 +00:00
|
|
|
return r;
|
|
|
|
}
|
2008-01-10 01:20:36 +00:00
|
|
|
}
|
|
|
|
|
2012-10-13 15:46:12 +00:00
|
|
|
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) {
|
2008-01-10 01:20:36 +00:00
|
|
|
// not supported
|
|
|
|
abort(s);
|
2007-12-11 00:48:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
2008-01-13 22:05:08 +00:00
|
|
|
Allocator* allocator;
|
|
|
|
void* context;
|
2007-12-11 00:48:09 +00:00
|
|
|
Segment* segment;
|
2008-01-10 01:20:36 +00:00
|
|
|
unsigned minimumFootprint;
|
2007-12-11 00:48:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace vm
|
|
|
|
|
|
|
|
#endif//ZONE_H
|