mirror of
https://github.com/corda/corda.git
synced 2025-01-05 20:54:13 +00:00
refactor memory allocation to allow better detection and handling of low-memory conditions
This commit is contained in:
parent
e6aea41a88
commit
0298865efa
@ -8,9 +8,9 @@ namespace vm {
|
|||||||
class Allocator {
|
class Allocator {
|
||||||
public:
|
public:
|
||||||
virtual ~Allocator() { }
|
virtual ~Allocator() { }
|
||||||
virtual void* tryAllocate(unsigned size) = 0;
|
virtual void* tryAllocate(void* context, unsigned size, bool executable) = 0;
|
||||||
virtual void* allocate(unsigned size) = 0;
|
virtual void* allocate(void* context, unsigned size, bool executable) = 0;
|
||||||
virtual void free(const void* p, unsigned size) = 0;
|
virtual void free(const void* p, unsigned size, bool executable) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
@ -123,10 +123,11 @@ Java_java_lang_ClassLoader_defineClass
|
|||||||
{
|
{
|
||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
uint8_t* buffer = static_cast<uint8_t*>(t->m->system->allocate(length));
|
uint8_t* buffer = static_cast<uint8_t*>
|
||||||
|
(t->m->heap->allocate(t, length, false));
|
||||||
memcpy(buffer, &byteArrayBody(t, *b, offset), length);
|
memcpy(buffer, &byteArrayBody(t, *b, offset), length);
|
||||||
object c = parseClass(t, buffer, length);
|
object c = parseClass(t, buffer, length);
|
||||||
t->m->system->free(buffer, length);
|
t->m->heap->free(buffer, length, false);
|
||||||
return makeLocalReference(t, c);
|
return makeLocalReference(t, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,27 +439,27 @@ class Context {
|
|||||||
|
|
||||||
Context(MyThread* t, object method, uint8_t* indirectCaller):
|
Context(MyThread* t, object method, uint8_t* indirectCaller):
|
||||||
t(t),
|
t(t),
|
||||||
zone(t->m->system, t->m->system, 16 * 1024),
|
zone(t->m->system, t->m->heap, t, false, 16 * 1024),
|
||||||
c(makeCompiler(t->m->system, &zone, indirectCaller)),
|
c(makeCompiler(t->m->system, t->m->heap, t, &zone, indirectCaller)),
|
||||||
method(method),
|
method(method),
|
||||||
objectPool(0),
|
objectPool(0),
|
||||||
traceLog(0),
|
traceLog(0),
|
||||||
visitTable(makeVisitTable(t, &zone, method)),
|
visitTable(makeVisitTable(t, &zone, method)),
|
||||||
rootTable(makeRootTable(t, &zone, method)),
|
rootTable(makeRootTable(t, &zone, method)),
|
||||||
eventLog(t->m->system, 1024),
|
eventLog(t->m->system, t->m->heap, t, 1024),
|
||||||
protector(this)
|
protector(this)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
Context(MyThread* t):
|
Context(MyThread* t):
|
||||||
t(t),
|
t(t),
|
||||||
zone(t->m->system, t->m->system, LikelyPageSizeInBytes),
|
zone(t->m->system, t->m->heap, t, false, LikelyPageSizeInBytes),
|
||||||
c(makeCompiler(t->m->system, &zone, 0)),
|
c(makeCompiler(t->m->system, t->m->heap, t, &zone, 0)),
|
||||||
method(0),
|
method(0),
|
||||||
objectPool(0),
|
objectPool(0),
|
||||||
traceLog(0),
|
traceLog(0),
|
||||||
visitTable(0),
|
visitTable(0),
|
||||||
rootTable(0),
|
rootTable(0),
|
||||||
eventLog(t->m->system, 0),
|
eventLog(t->m->system, t->m->heap, t, 0),
|
||||||
protector(this)
|
protector(this)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@ -3644,7 +3644,7 @@ finish(MyThread* t, Context* context, const char* name)
|
|||||||
unsigned size = count + singletonMaskSize(count);
|
unsigned size = count + singletonMaskSize(count);
|
||||||
object result = allocate3
|
object result = allocate3
|
||||||
(t, codeAllocator(t), Machine::ImmortalAllocation,
|
(t, codeAllocator(t), Machine::ImmortalAllocation,
|
||||||
SingletonBody + (size * BytesPerWord), true);
|
SingletonBody + (size * BytesPerWord), true, true);
|
||||||
initSingleton(t, result, size, true);
|
initSingleton(t, result, size, true);
|
||||||
mark(t, result, 0);
|
mark(t, result, 0);
|
||||||
singletonMask(t, result)[0] = 1;
|
singletonMask(t, result)[0] = 1;
|
||||||
@ -4349,21 +4349,22 @@ class SegFaultHandler: public System::SignalHandler {
|
|||||||
|
|
||||||
class MyProcessor: public Processor {
|
class MyProcessor: public Processor {
|
||||||
public:
|
public:
|
||||||
MyProcessor(System* s):
|
MyProcessor(System* s, Allocator* allocator):
|
||||||
s(s),
|
s(s),
|
||||||
|
allocator(allocator),
|
||||||
defaultCompiled(0),
|
defaultCompiled(0),
|
||||||
nativeCompiled(0),
|
nativeCompiled(0),
|
||||||
addressTable(0),
|
addressTable(0),
|
||||||
addressCount(0),
|
addressCount(0),
|
||||||
indirectCaller(0),
|
indirectCaller(0),
|
||||||
indirectCallerSize(0),
|
indirectCallerSize(0),
|
||||||
codeAllocator(s, s->codeAllocator(), 64 * 1024)
|
codeAllocator(s, allocator, 0, true, 64 * 1024)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual Thread*
|
virtual Thread*
|
||||||
makeThread(Machine* m, object javaThread, Thread* parent)
|
makeThread(Machine* m, object javaThread, Thread* parent)
|
||||||
{
|
{
|
||||||
MyThread* t = new (s->allocate(sizeof(MyThread)))
|
MyThread* t = new (m->heap->allocate(parent, sizeof(MyThread), false))
|
||||||
MyThread(m, javaThread, parent);
|
MyThread(m, javaThread, parent);
|
||||||
t->init();
|
t->init();
|
||||||
return t;
|
return t;
|
||||||
@ -4501,8 +4502,9 @@ class MyProcessor: public Processor {
|
|||||||
{
|
{
|
||||||
if (o) {
|
if (o) {
|
||||||
MyThread* t = static_cast<MyThread*>(vmt);
|
MyThread* t = static_cast<MyThread*>(vmt);
|
||||||
|
PROTECT(t, o);
|
||||||
|
|
||||||
Reference* r = new (t->m->system->allocate(sizeof(Reference)))
|
Reference* r = new (t->m->heap->allocate(t, sizeof(Reference), false))
|
||||||
Reference(o, &(t->reference));
|
Reference(o, &(t->reference));
|
||||||
|
|
||||||
return &(r->target);
|
return &(r->target);
|
||||||
@ -4611,7 +4613,7 @@ class MyProcessor: public Processor {
|
|||||||
vm::dispose(t, t->reference);
|
vm::dispose(t, t->reference);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->free(t, sizeof(*t));
|
t->m->heap->free(t, sizeof(*t), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
@ -4619,10 +4621,11 @@ class MyProcessor: public Processor {
|
|||||||
|
|
||||||
s->handleSegFault(0);
|
s->handleSegFault(0);
|
||||||
|
|
||||||
s->free(this, sizeof(*this));
|
allocator->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
|
Allocator* allocator;
|
||||||
object defaultCompiled;
|
object defaultCompiled;
|
||||||
object nativeCompiled;
|
object nativeCompiled;
|
||||||
object addressTable;
|
object addressTable;
|
||||||
@ -4659,11 +4662,11 @@ processor(MyThread* t)
|
|||||||
if (Verbose) {
|
if (Verbose) {
|
||||||
logCompile(p->indirectCaller, c->codeSize(), 0, "indirect caller", 0);
|
logCompile(p->indirectCaller, c->codeSize(), 0, "indirect caller", 0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
p->segFaultHandler.m = t->m;
|
p->segFaultHandler.m = t->m;
|
||||||
expect(t, t->m->system->success
|
expect(t, t->m->system->success
|
||||||
(t->m->system->handleSegFault(&(p->segFaultHandler))));
|
(t->m->system->handleSegFault(&(p->segFaultHandler))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -4802,9 +4805,10 @@ codeAllocator(MyThread* t) {
|
|||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
Processor*
|
Processor*
|
||||||
makeProcessor(System* system)
|
makeProcessor(System* system, Allocator* allocator)
|
||||||
{
|
{
|
||||||
return new (system->allocate(sizeof(MyProcessor))) MyProcessor(system);
|
return new (allocator->allocate(0, sizeof(MyProcessor), false))
|
||||||
|
MyProcessor(system, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
@ -137,11 +137,12 @@ class RegisterData {
|
|||||||
|
|
||||||
class Context {
|
class Context {
|
||||||
public:
|
public:
|
||||||
Context(System* s, Zone* zone, void* indirectCaller):
|
Context(System* s, Allocator* allocator, void* allocatorContext, Zone* zone,
|
||||||
|
void* indirectCaller):
|
||||||
s(s),
|
s(s),
|
||||||
constantPool(s, BytesPerWord * 32),
|
constantPool(s, allocator, allocatorContext, BytesPerWord * 32),
|
||||||
plan(s, 1024),
|
plan(s, allocator, allocatorContext, 1024),
|
||||||
code(s, 1024),
|
code(s, allocator, allocatorContext, 1024),
|
||||||
zone(zone),
|
zone(zone),
|
||||||
indirectCaller(reinterpret_cast<intptr_t>(indirectCaller)),
|
indirectCaller(reinterpret_cast<intptr_t>(indirectCaller)),
|
||||||
segmentTable(0),
|
segmentTable(0),
|
||||||
@ -2381,8 +2382,9 @@ writeCode(Context* c)
|
|||||||
|
|
||||||
class MyCompiler: public Compiler {
|
class MyCompiler: public Compiler {
|
||||||
public:
|
public:
|
||||||
MyCompiler(System* s, Zone* zone, void* indirectCaller):
|
MyCompiler(System* s, Allocator* allocator, void* allocatorContext,
|
||||||
c(s, zone, indirectCaller)
|
Zone* zone, void* indirectCaller):
|
||||||
|
c(s, allocator, allocatorContext, zone, indirectCaller)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual Promise* machineIp(unsigned logicalIp) {
|
virtual Promise* machineIp(unsigned logicalIp) {
|
||||||
@ -2868,10 +2870,11 @@ MyPromise::value(Compiler* compiler)
|
|||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
Compiler*
|
Compiler*
|
||||||
makeCompiler(System* system, Zone* zone, void* indirectCaller)
|
makeCompiler(System* system, Allocator* allocator, void* allocatorContext,
|
||||||
|
Zone* zone, void* indirectCaller)
|
||||||
{
|
{
|
||||||
return new (zone->allocate(sizeof(MyCompiler)))
|
return new (zone->allocate(sizeof(MyCompiler)))
|
||||||
MyCompiler(system, zone, indirectCaller);
|
MyCompiler(system, allocator, allocatorContext, zone, indirectCaller);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace v
|
} // namespace v
|
||||||
|
@ -141,7 +141,8 @@ class Compiler {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Compiler*
|
Compiler*
|
||||||
makeCompiler(System* system, Zone* zone, void* indirectCaller);
|
makeCompiler(System* system, Allocator* allocator, void* allocatorContext,
|
||||||
|
Zone* zone, void* indirectCaller);
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
|
||||||
|
@ -6,6 +6,20 @@ using namespace vm;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
void*
|
||||||
|
allocate(System* s, unsigned size)
|
||||||
|
{
|
||||||
|
void* p = s->tryAllocate(size, false);
|
||||||
|
if (p == 0) abort();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
free(System* s, const void* p, unsigned size)
|
||||||
|
{
|
||||||
|
s->free(p, size, false);
|
||||||
|
}
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
append(System* s, unsigned* length, const char* a, const char* b,
|
append(System* s, unsigned* length, const char* a, const char* b,
|
||||||
const char* c)
|
const char* c)
|
||||||
@ -14,7 +28,7 @@ append(System* s, unsigned* length, const char* a, const char* b,
|
|||||||
unsigned bl = strlen(b);
|
unsigned bl = strlen(b);
|
||||||
unsigned cl = strlen(c);
|
unsigned cl = strlen(c);
|
||||||
*length = al + bl + cl;
|
*length = al + bl + cl;
|
||||||
char* p = static_cast<char*>(s->allocate(*length + 1));
|
char* p = static_cast<char*>(allocate(s, *length + 1));
|
||||||
memcpy(p, a, al);
|
memcpy(p, a, al);
|
||||||
memcpy(p + al, b, bl);
|
memcpy(p + al, b, bl);
|
||||||
memcpy(p + al + bl, c, cl + 1);
|
memcpy(p + al + bl, c, cl + 1);
|
||||||
@ -26,7 +40,7 @@ copy(System* s, unsigned* length, const char* a)
|
|||||||
{
|
{
|
||||||
unsigned al = strlen(a);
|
unsigned al = strlen(a);
|
||||||
*length = al;
|
*length = al;
|
||||||
char* p = static_cast<char*>(s->allocate(*length + 1));
|
char* p = static_cast<char*>(allocate(s, *length + 1));
|
||||||
memcpy(p, a, al + 1);
|
memcpy(p, a, al + 1);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -63,7 +77,7 @@ class DirectoryElement: public Element {
|
|||||||
const char* file = append(s, &length, this->name, "/", name);
|
const char* file = append(s, &length, this->name, "/", name);
|
||||||
System::Region* region;
|
System::Region* region;
|
||||||
System::Status status = s->map(®ion, file);
|
System::Status status = s->map(®ion, file);
|
||||||
s->free(file, length + 1);
|
free(s, file, length + 1);
|
||||||
|
|
||||||
if (s->success(status)) {
|
if (s->success(status)) {
|
||||||
return region;
|
return region;
|
||||||
@ -76,13 +90,13 @@ class DirectoryElement: public Element {
|
|||||||
unsigned length;
|
unsigned length;
|
||||||
const char* file = append(s, &length, this->name, "/", name);
|
const char* file = append(s, &length, this->name, "/", name);
|
||||||
System::FileType type = s->identify(file);
|
System::FileType type = s->identify(file);
|
||||||
s->free(file, length + 1);
|
free(s, file, length + 1);
|
||||||
return type != System::DoesNotExist;
|
return type != System::DoesNotExist;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
s->free(name, nameLength + 1);
|
free(s, name, nameLength + 1);
|
||||||
s->free(this, sizeof(*this));
|
free(s, this, sizeof(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -107,7 +121,7 @@ class PointerRegion: public System::Region {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
s->free(this, sizeof(*this));
|
free(s, this, sizeof(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -131,7 +145,7 @@ class DataRegion: public System::Region {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
s->free(this, sizeof(*this) + length_);
|
free(s, this, sizeof(*this) + length_);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -163,7 +177,7 @@ class JarIndex {
|
|||||||
s(s),
|
s(s),
|
||||||
capacity(capacity),
|
capacity(capacity),
|
||||||
position(0),
|
position(0),
|
||||||
nodes(static_cast<Node*>(s->allocate(sizeof(Node) * capacity)))
|
nodes(static_cast<Node*>(allocate(s, sizeof(Node) * capacity)))
|
||||||
{
|
{
|
||||||
memset(table, 0, sizeof(Node*) * capacity);
|
memset(table, 0, sizeof(Node*) * capacity);
|
||||||
}
|
}
|
||||||
@ -220,7 +234,7 @@ class JarIndex {
|
|||||||
|
|
||||||
static JarIndex* make(System* s, unsigned capacity) {
|
static JarIndex* make(System* s, unsigned capacity) {
|
||||||
return new
|
return new
|
||||||
(s->allocate(sizeof(JarIndex) + (sizeof(Node*) * capacity)))
|
(allocate(s, sizeof(JarIndex) + (sizeof(Node*) * capacity)))
|
||||||
JarIndex(s, capacity);
|
JarIndex(s, capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,13 +290,13 @@ class JarIndex {
|
|||||||
const uint8_t* p = n->entry;
|
const uint8_t* p = n->entry;
|
||||||
switch (compressionMethod(p)) {
|
switch (compressionMethod(p)) {
|
||||||
case Stored: {
|
case Stored: {
|
||||||
return new (s->allocate(sizeof(PointerRegion)))
|
return new (allocate(s, sizeof(PointerRegion)))
|
||||||
PointerRegion(s, fileData(p), compressedSize(p));
|
PointerRegion(s, fileData(p), compressedSize(p));
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Deflated: {
|
case Deflated: {
|
||||||
DataRegion* region = new
|
DataRegion* region = new
|
||||||
(s->allocate(sizeof(DataRegion) + uncompressedSize(p)))
|
(allocate(s, sizeof(DataRegion) + uncompressedSize(p)))
|
||||||
DataRegion(s, uncompressedSize(p));
|
DataRegion(s, uncompressedSize(p));
|
||||||
|
|
||||||
z_stream zStream; memset(&zStream, 0, sizeof(z_stream));
|
z_stream zStream; memset(&zStream, 0, sizeof(z_stream));
|
||||||
@ -317,8 +331,8 @@ class JarIndex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
s->free(nodes, sizeof(Node) * capacity);
|
free(s, nodes, sizeof(Node) * capacity);
|
||||||
s->free(this, sizeof(*this) + (sizeof(Node*) * capacity));
|
free(s, this, sizeof(*this) + (sizeof(Node*) * capacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -361,14 +375,14 @@ class JarElement: public Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
s->free(name, nameLength + 1);
|
free(s, name, nameLength + 1);
|
||||||
if (index) {
|
if (index) {
|
||||||
index->dispose();
|
index->dispose();
|
||||||
}
|
}
|
||||||
if (region) {
|
if (region) {
|
||||||
region->dispose();
|
region->dispose();
|
||||||
}
|
}
|
||||||
s->free(this, sizeof(*this));
|
free(s, this, sizeof(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -396,7 +410,7 @@ class BuiltinElement: public JarElement {
|
|||||||
unsigned size;
|
unsigned size;
|
||||||
uint8_t* data = function(&size);
|
uint8_t* data = function(&size);
|
||||||
if (data) {
|
if (data) {
|
||||||
region = new (s->allocate(sizeof(PointerRegion)))
|
region = new (allocate(s, sizeof(PointerRegion)))
|
||||||
PointerRegion(s, data, size);
|
PointerRegion(s, data, size);
|
||||||
index = JarIndex::open(s, region);
|
index = JarIndex::open(s, region);
|
||||||
}
|
}
|
||||||
@ -444,30 +458,30 @@ parsePath(System* s, const char* path)
|
|||||||
|
|
||||||
Element* e;
|
Element* e;
|
||||||
if (*token.s == '[' and token.s[token.length - 1] == ']') {
|
if (*token.s == '[' and token.s[token.length - 1] == ']') {
|
||||||
char* name = static_cast<char*>(s->allocate(token.length - 1));
|
char* name = static_cast<char*>(allocate(s, token.length - 1));
|
||||||
memcpy(name, token.s + 1, token.length - 1);
|
memcpy(name, token.s + 1, token.length - 1);
|
||||||
name[token.length - 2] = 0;
|
name[token.length - 2] = 0;
|
||||||
|
|
||||||
e = new (s->allocate(sizeof(BuiltinElement)))
|
e = new (allocate(s, sizeof(BuiltinElement)))
|
||||||
BuiltinElement(s, name, token.length - 2);
|
BuiltinElement(s, name, token.length - 2);
|
||||||
} else {
|
} else {
|
||||||
char* name = static_cast<char*>(s->allocate(token.length + 1));
|
char* name = static_cast<char*>(allocate(s, token.length + 1));
|
||||||
memcpy(name, token.s, token.length);
|
memcpy(name, token.s, token.length);
|
||||||
name[token.length] = 0;
|
name[token.length] = 0;
|
||||||
|
|
||||||
switch (s->identify(name)) {
|
switch (s->identify(name)) {
|
||||||
case System::File: {
|
case System::File: {
|
||||||
e = new (s->allocate(sizeof(JarElement)))
|
e = new (allocate(s, sizeof(JarElement)))
|
||||||
JarElement(s, name, token.length);
|
JarElement(s, name, token.length);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case System::Directory: {
|
case System::Directory: {
|
||||||
e = new (s->allocate(sizeof(DirectoryElement)))
|
e = new (allocate(s, sizeof(DirectoryElement)))
|
||||||
DirectoryElement(s, name, token.length);
|
DirectoryElement(s, name, token.length);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
s->free(name, token.length + 1);
|
free(s, name, token.length + 1);
|
||||||
e = 0;
|
e = 0;
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
@ -525,8 +539,8 @@ class MyFinder: public Finder {
|
|||||||
e = e->next;
|
e = e->next;
|
||||||
t->dispose();
|
t->dispose();
|
||||||
}
|
}
|
||||||
system->free(pathString, pathStringLength + 1);
|
free(system, pathString, pathStringLength + 1);
|
||||||
system->free(this, sizeof(*this));
|
free(system, this, sizeof(*this));
|
||||||
}
|
}
|
||||||
|
|
||||||
System* system;
|
System* system;
|
||||||
@ -542,7 +556,7 @@ namespace vm {
|
|||||||
Finder*
|
Finder*
|
||||||
makeFinder(System* s, const char* path)
|
makeFinder(System* s, const char* path)
|
||||||
{
|
{
|
||||||
return new (s->allocate(sizeof(MyFinder))) MyFinder(s, path);
|
return new (allocate(s, sizeof(MyFinder))) MyFinder(s, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
#include "allocator.h"
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
|
155
src/heap.cpp
155
src/heap.cpp
@ -17,11 +17,29 @@ const unsigned Top = ~static_cast<unsigned>(0);
|
|||||||
const unsigned InitialGen2CapacityInBytes = 4 * 1024 * 1024;
|
const unsigned InitialGen2CapacityInBytes = 4 * 1024 * 1024;
|
||||||
const unsigned InitialTenuredFixieCeilingInBytes = 4 * 1024 * 1024;
|
const unsigned InitialTenuredFixieCeilingInBytes = 4 * 1024 * 1024;
|
||||||
|
|
||||||
|
const unsigned MajorCollectionInterval = 16;
|
||||||
|
|
||||||
const bool Verbose = false;
|
const bool Verbose = false;
|
||||||
const bool Verbose2 = false;
|
const bool Verbose2 = false;
|
||||||
const bool Debug = false;
|
const bool Debug = false;
|
||||||
const bool DebugFixies = false;
|
const bool DebugFixies = false;
|
||||||
|
|
||||||
|
#define ACQUIRE(x) MutexLock MAKE_NAME(monitorLock_) (x)
|
||||||
|
|
||||||
|
class MutexLock {
|
||||||
|
public:
|
||||||
|
MutexLock(System::Mutex* m): m(m) {
|
||||||
|
m->acquire();
|
||||||
|
}
|
||||||
|
|
||||||
|
~MutexLock() {
|
||||||
|
m->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
System::Mutex* m;
|
||||||
|
};
|
||||||
|
|
||||||
class Context;
|
class Context;
|
||||||
|
|
||||||
void NO_RETURN abort(Context*);
|
void NO_RETURN abort(Context*);
|
||||||
@ -30,6 +48,9 @@ void assert(Context*, bool);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
System* system(Context*);
|
System* system(Context*);
|
||||||
|
void* tryAllocate(Context* c, void* clientContext, unsigned size,
|
||||||
|
bool executable);
|
||||||
|
void free(Context* c, const void* p, unsigned size, bool executable);
|
||||||
|
|
||||||
inline void*
|
inline void*
|
||||||
get(void* o, unsigned offsetInWords)
|
get(void* o, unsigned offsetInWords)
|
||||||
@ -284,8 +305,9 @@ class Segment {
|
|||||||
capacity_ = desired;
|
capacity_ = desired;
|
||||||
while (data == 0) {
|
while (data == 0) {
|
||||||
data = static_cast<uintptr_t*>
|
data = static_cast<uintptr_t*>
|
||||||
(system(context)->tryAllocate
|
(tryAllocate
|
||||||
((capacity_ + mapFootprint(capacity_)) * BytesPerWord));
|
(context, 0, (capacity_ + mapFootprint(capacity_)) * BytesPerWord,
|
||||||
|
false));
|
||||||
|
|
||||||
if (data == 0) {
|
if (data == 0) {
|
||||||
if (capacity_ > minimum) {
|
if (capacity_ > minimum) {
|
||||||
@ -323,8 +345,8 @@ class Segment {
|
|||||||
|
|
||||||
void replaceWith(Segment* s) {
|
void replaceWith(Segment* s) {
|
||||||
if (data) {
|
if (data) {
|
||||||
system(context)->free
|
free(context, data,
|
||||||
(data, (capacity() + mapFootprint(capacity())) * BytesPerWord);
|
(capacity() + mapFootprint(capacity())) * BytesPerWord, false);
|
||||||
}
|
}
|
||||||
data = s->data;
|
data = s->data;
|
||||||
s->data = 0;
|
s->data = 0;
|
||||||
@ -375,8 +397,8 @@ class Segment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
system(context)->free
|
free(context, data,
|
||||||
(data, (capacity() + mapFootprint(capacity())) * BytesPerWord);
|
(capacity() + mapFootprint(capacity())) * BytesPerWord, false);
|
||||||
data = 0;
|
data = 0;
|
||||||
map = 0;
|
map = 0;
|
||||||
}
|
}
|
||||||
@ -468,9 +490,12 @@ free(Context* c, Fixie** fixies);
|
|||||||
|
|
||||||
class Context {
|
class Context {
|
||||||
public:
|
public:
|
||||||
Context(System* system, Heap::Client* client):
|
Context(System* system, unsigned limit):
|
||||||
system(system),
|
system(system),
|
||||||
client(client),
|
client(0),
|
||||||
|
count(0),
|
||||||
|
limit(limit),
|
||||||
|
lock(0),
|
||||||
|
|
||||||
ageMap(&gen1, max(1, log(TenureThreshold)), 1, 0, false),
|
ageMap(&gen1, max(1, log(TenureThreshold)), 1, 0, false),
|
||||||
gen1(this, &ageMap, 0, 0),
|
gen1(this, &ageMap, 0, 0),
|
||||||
@ -507,24 +532,38 @@ class Context {
|
|||||||
markedFixies(0),
|
markedFixies(0),
|
||||||
visitedFixies(0),
|
visitedFixies(0),
|
||||||
|
|
||||||
|
majorCollectionCountdown(0),
|
||||||
|
|
||||||
lastCollectionTime(system->now()),
|
lastCollectionTime(system->now()),
|
||||||
totalCollectionTime(0),
|
totalCollectionTime(0),
|
||||||
totalTime(0)
|
totalTime(0)
|
||||||
{ }
|
{
|
||||||
|
if (not system->success(system->make(&lock))) {
|
||||||
|
system->abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
gen1.dispose();
|
gen1.dispose();
|
||||||
nextGen1.dispose();
|
nextGen1.dispose();
|
||||||
gen2.dispose();
|
gen2.dispose();
|
||||||
nextGen2.dispose();
|
nextGen2.dispose();
|
||||||
|
lock->dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void disposeFixies() {
|
||||||
free(this, &tenuredFixies);
|
free(this, &tenuredFixies);
|
||||||
free(this, &dirtyTenuredFixies);
|
free(this, &dirtyTenuredFixies);
|
||||||
free(this, &fixies);
|
free(this, &fixies);
|
||||||
client->dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
System* system;
|
System* system;
|
||||||
Heap::Client* client;
|
Heap::Client* client;
|
||||||
|
|
||||||
|
unsigned count;
|
||||||
|
unsigned limit;
|
||||||
|
|
||||||
|
System::Mutex* lock;
|
||||||
|
|
||||||
Segment::Map ageMap;
|
Segment::Map ageMap;
|
||||||
Segment gen1;
|
Segment gen1;
|
||||||
@ -561,6 +600,8 @@ class Context {
|
|||||||
Fixie* markedFixies;
|
Fixie* markedFixies;
|
||||||
Fixie* visitedFixies;
|
Fixie* visitedFixies;
|
||||||
|
|
||||||
|
unsigned majorCollectionCountdown;
|
||||||
|
|
||||||
int64_t lastCollectionTime;
|
int64_t lastCollectionTime;
|
||||||
int64_t totalCollectionTime;
|
int64_t totalCollectionTime;
|
||||||
int64_t totalTime;
|
int64_t totalTime;
|
||||||
@ -706,7 +747,7 @@ free(Context* c, Fixie** fixies)
|
|||||||
if (DebugFixies) {
|
if (DebugFixies) {
|
||||||
fprintf(stderr, "free fixie %p\n", f);
|
fprintf(stderr, "free fixie %p\n", f);
|
||||||
}
|
}
|
||||||
c->system->free(f, f->totalSize());
|
free(c, f, f->totalSize(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1459,6 +1500,17 @@ collect(Context* c, unsigned footprint)
|
|||||||
}
|
}
|
||||||
|
|
||||||
c->mode = Heap::MajorCollection;
|
c->mode = Heap::MajorCollection;
|
||||||
|
} else if (c->mode == Heap::MinorCollection
|
||||||
|
and c->majorCollectionCountdown)
|
||||||
|
{
|
||||||
|
-- c->majorCollectionCountdown;
|
||||||
|
if (c->majorCollectionCountdown == 0) {
|
||||||
|
if (Verbose) {
|
||||||
|
fprintf(stderr, "countdown causes ");
|
||||||
|
}
|
||||||
|
|
||||||
|
c->mode = Heap::MajorCollection;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t then;
|
int64_t then;
|
||||||
@ -1475,6 +1527,7 @@ collect(Context* c, unsigned footprint)
|
|||||||
initNextGen1(c, footprint);
|
initNextGen1(c, footprint);
|
||||||
|
|
||||||
if (c->mode == Heap::MajorCollection) {
|
if (c->mode == Heap::MajorCollection) {
|
||||||
|
c->majorCollectionCountdown = MajorCollectionInterval;
|
||||||
initNextGen2(c);
|
initNextGen2(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1525,9 +1578,63 @@ collect(Context* c, unsigned footprint)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* tryAllocate(Context* c, void* clientContext, unsigned size,
|
||||||
|
bool executable)
|
||||||
|
{
|
||||||
|
ACQUIRE(c->lock);
|
||||||
|
|
||||||
|
if (clientContext and size + c->count >= c->limit) {
|
||||||
|
c->client->collect(clientContext, Heap::MajorCollection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size + c->count < c->limit) {
|
||||||
|
void* p = c->system->tryAllocate(size, executable);
|
||||||
|
if (p) {
|
||||||
|
c->count += size;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(Context* c, const void* p, unsigned size, bool executable) {
|
||||||
|
ACQUIRE(c->lock);
|
||||||
|
|
||||||
|
expect(c->system, c->count >= size);
|
||||||
|
c->system->free(p, size, executable);
|
||||||
|
c->count -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_(Context* c, const void* p, unsigned size, bool executable) {
|
||||||
|
free(c, p, size, executable);
|
||||||
|
}
|
||||||
|
|
||||||
class MyHeap: public Heap {
|
class MyHeap: public Heap {
|
||||||
public:
|
public:
|
||||||
MyHeap(System* system, Heap::Client* client): c(system, client) { }
|
MyHeap(System* system, unsigned limit):
|
||||||
|
c(system, limit)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual void setClient(Heap::Client* client) {
|
||||||
|
assert(&c, c.client == 0);
|
||||||
|
c.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void* tryAllocate(void* clientContext, unsigned size,
|
||||||
|
bool executable)
|
||||||
|
{
|
||||||
|
return ::tryAllocate(&c, clientContext, size, executable);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void* allocate(void* clientContext, unsigned size, bool executable) {
|
||||||
|
void* p = ::tryAllocate(&c, clientContext, size, executable);
|
||||||
|
expect(c.system, p);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void free(const void* p, unsigned size, bool executable) {
|
||||||
|
free_(&c, p, size, executable);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void collect(CollectionType type, unsigned footprint) {
|
virtual void collect(CollectionType type, unsigned footprint) {
|
||||||
c.mode = type;
|
c.mode = type;
|
||||||
@ -1535,19 +1642,21 @@ class MyHeap: public Heap {
|
|||||||
::collect(&c, footprint);
|
::collect(&c, footprint);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
|
virtual void* allocateFixed(Allocator* allocator, void* clientContext,
|
||||||
bool objectMask, unsigned* totalInBytes)
|
unsigned sizeInWords, bool objectMask,
|
||||||
|
unsigned* totalInBytes)
|
||||||
{
|
{
|
||||||
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
|
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
|
||||||
return (new (allocator->allocate(*totalInBytes))
|
return (new (allocator->allocate(clientContext, *totalInBytes, false))
|
||||||
Fixie(sizeInWords, objectMask, &(c.fixies), false))->body();
|
Fixie(sizeInWords, objectMask, &(c.fixies), false))->body();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* allocateImmortal(Allocator* allocator, unsigned sizeInWords,
|
virtual void* allocateImmortal(Allocator* allocator, void* clientContext,
|
||||||
|
unsigned sizeInWords, bool executable,
|
||||||
bool objectMask, unsigned* totalInBytes)
|
bool objectMask, unsigned* totalInBytes)
|
||||||
{
|
{
|
||||||
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
|
*totalInBytes = Fixie::totalSize(sizeInWords, objectMask);
|
||||||
return (new (allocator->allocate(*totalInBytes))
|
return (new (allocator->allocate(clientContext, *totalInBytes, executable))
|
||||||
Fixie(sizeInWords, objectMask, &(c.tenuredFixies), true))->body();
|
Fixie(sizeInWords, objectMask, &(c.tenuredFixies), true))->body();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1650,9 +1759,14 @@ class MyHeap: public Heap {
|
|||||||
return c.mode;
|
return c.mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void disposeFixies() {
|
||||||
|
c.disposeFixies();
|
||||||
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
c.dispose();
|
c.dispose();
|
||||||
c.system->free(this, sizeof(*this));
|
assert(&c, c.count == 0);
|
||||||
|
c.system->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Context c;
|
Context c;
|
||||||
@ -1663,9 +1777,10 @@ class MyHeap: public Heap {
|
|||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
Heap*
|
Heap*
|
||||||
makeHeap(System* system, Heap::Client* client)
|
makeHeap(System* system, unsigned limit)
|
||||||
{
|
{
|
||||||
return new (system->allocate(sizeof(MyHeap))) MyHeap(system, client);
|
return new (system->tryAllocate(sizeof(MyHeap), false))
|
||||||
|
MyHeap(system, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
18
src/heap.h
18
src/heap.h
@ -2,11 +2,11 @@
|
|||||||
#define HEAP_H
|
#define HEAP_H
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "zone.h"
|
#include "allocator.h"
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
class Heap {
|
class Heap: public Allocator {
|
||||||
public:
|
public:
|
||||||
enum CollectionType {
|
enum CollectionType {
|
||||||
MinorCollection,
|
MinorCollection,
|
||||||
@ -35,20 +35,23 @@ class Heap {
|
|||||||
class Client {
|
class Client {
|
||||||
public:
|
public:
|
||||||
virtual ~Client() { }
|
virtual ~Client() { }
|
||||||
|
virtual void collect(void* context, CollectionType type) = 0;
|
||||||
virtual void visitRoots(Visitor*) = 0;
|
virtual void visitRoots(Visitor*) = 0;
|
||||||
virtual bool isFixed(void*) = 0;
|
virtual bool isFixed(void*) = 0;
|
||||||
virtual unsigned sizeInWords(void*) = 0;
|
virtual unsigned sizeInWords(void*) = 0;
|
||||||
virtual unsigned copiedSizeInWords(void*) = 0;
|
virtual unsigned copiedSizeInWords(void*) = 0;
|
||||||
virtual void copy(void*, void*) = 0;
|
virtual void copy(void*, void*) = 0;
|
||||||
virtual void walk(void*, Walker*) = 0;
|
virtual void walk(void*, Walker*) = 0;
|
||||||
virtual void dispose() = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~Heap() { }
|
virtual ~Heap() { }
|
||||||
|
virtual void setClient(Client* client) = 0;
|
||||||
virtual void collect(CollectionType type, unsigned footprint) = 0;
|
virtual void collect(CollectionType type, unsigned footprint) = 0;
|
||||||
virtual void* allocateFixed(Allocator* allocator, unsigned sizeInWords,
|
virtual void* allocateFixed(Allocator* allocator, void* context,
|
||||||
bool objectMask, unsigned* totalInBytes) = 0;
|
unsigned sizeInWords, bool objectMask,
|
||||||
virtual void* allocateImmortal(Allocator* allocator, unsigned sizeInWords,
|
unsigned* totalInBytes) = 0;
|
||||||
|
virtual void* allocateImmortal(Allocator* allocator, void* context,
|
||||||
|
unsigned sizeInWords, bool executable,
|
||||||
bool objectMask, unsigned* totalInBytes) = 0;
|
bool objectMask, unsigned* totalInBytes) = 0;
|
||||||
virtual bool needsMark(void* p) = 0;
|
virtual bool needsMark(void* p) = 0;
|
||||||
virtual void mark(void* p, unsigned offset, unsigned count) = 0;
|
virtual void mark(void* p, unsigned offset, unsigned count) = 0;
|
||||||
@ -56,10 +59,11 @@ class Heap {
|
|||||||
virtual void* follow(void* p) = 0;
|
virtual void* follow(void* p) = 0;
|
||||||
virtual Status status(void* p) = 0;
|
virtual Status status(void* p) = 0;
|
||||||
virtual CollectionType collectionType() = 0;
|
virtual CollectionType collectionType() = 0;
|
||||||
|
virtual void disposeFixies() = 0;
|
||||||
virtual void dispose() = 0;
|
virtual void dispose() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Heap* makeHeap(System* system, Heap::Client* client);
|
Heap* makeHeap(System* system, unsigned limit);
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
|
||||||
|
@ -2194,7 +2194,7 @@ interpret(Thread* t)
|
|||||||
} goto loop;
|
} goto loop;
|
||||||
|
|
||||||
case lushr: {
|
case lushr: {
|
||||||
int64_t b = popLong(t);
|
int64_t b = popInt(t);
|
||||||
uint64_t a = popLong(t);
|
uint64_t a = popLong(t);
|
||||||
|
|
||||||
pushLong(t, a >> b);
|
pushLong(t, a >> b);
|
||||||
@ -2812,14 +2812,14 @@ invoke(Thread* t, object method)
|
|||||||
|
|
||||||
class MyProcessor: public Processor {
|
class MyProcessor: public Processor {
|
||||||
public:
|
public:
|
||||||
MyProcessor(System* s):
|
MyProcessor(System* s, Allocator* allocator):
|
||||||
s(s)
|
s(s), allocator(allocator)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual vm::Thread*
|
virtual vm::Thread*
|
||||||
makeThread(Machine* m, object javaThread, vm::Thread* parent)
|
makeThread(Machine* m, object javaThread, vm::Thread* parent)
|
||||||
{
|
{
|
||||||
Thread* t = new (s->allocate(sizeof(Thread)))
|
Thread* t = new (m->heap->allocate(parent, sizeof(Thread), false))
|
||||||
Thread(m, javaThread, parent);
|
Thread(m, javaThread, parent);
|
||||||
t->init();
|
t->init();
|
||||||
return t;
|
return t;
|
||||||
@ -3016,14 +3016,15 @@ class MyProcessor: public Processor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose(vm::Thread* t) {
|
virtual void dispose(vm::Thread* t) {
|
||||||
s->free(t, sizeof(Thread));
|
t->m->heap->free(t, sizeof(Thread), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
s->free(this, sizeof(*this));
|
allocator->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
|
Allocator* allocator;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -3031,9 +3032,10 @@ class MyProcessor: public Processor {
|
|||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
Processor*
|
Processor*
|
||||||
makeProcessor(System* system)
|
makeProcessor(System* system, Allocator* allocator)
|
||||||
{
|
{
|
||||||
return new (system->allocate(sizeof(MyProcessor))) MyProcessor(system);
|
return new (allocator->allocate(0, sizeof(MyProcessor), false))
|
||||||
|
MyProcessor(system, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
@ -19,6 +19,7 @@ jint JNICALL
|
|||||||
DestroyJavaVM(Machine* m)
|
DestroyJavaVM(Machine* m)
|
||||||
{
|
{
|
||||||
System* s = m->system;
|
System* s = m->system;
|
||||||
|
Heap* h = m->heap;
|
||||||
Processor* p = m->processor;
|
Processor* p = m->processor;
|
||||||
Finder* f = m->finder;
|
Finder* f = m->finder;
|
||||||
Thread* t = m->rootThread;
|
Thread* t = m->rootThread;
|
||||||
@ -28,7 +29,9 @@ DestroyJavaVM(Machine* m)
|
|||||||
t->exit();
|
t->exit();
|
||||||
|
|
||||||
m->dispose();
|
m->dispose();
|
||||||
|
h->disposeFixies();
|
||||||
p->dispose();
|
p->dispose();
|
||||||
|
h->dispose();
|
||||||
f->dispose();
|
f->dispose();
|
||||||
s->dispose();
|
s->dispose();
|
||||||
|
|
||||||
@ -88,7 +91,7 @@ GetStringUTFChars(Thread* t, jstring s, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
char* chars = static_cast<char*>
|
char* chars = static_cast<char*>
|
||||||
(t->m->system->allocate(stringLength(t, *s) + 1));
|
(t->m->heap->allocate(t, stringLength(t, *s) + 1, false));
|
||||||
stringChars(t, *s, chars);
|
stringChars(t, *s, chars);
|
||||||
|
|
||||||
if (isCopy) *isCopy = true;
|
if (isCopy) *isCopy = true;
|
||||||
@ -98,7 +101,7 @@ GetStringUTFChars(Thread* t, jstring s, jboolean* isCopy)
|
|||||||
void JNICALL
|
void JNICALL
|
||||||
ReleaseStringUTFChars(Thread* t, jstring s, const char* chars)
|
ReleaseStringUTFChars(Thread* t, jstring s, const char* chars)
|
||||||
{
|
{
|
||||||
t->m->system->free(chars, stringLength(t, *s) + 1);
|
t->m->heap->free(chars, stringLength(t, *s) + 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
jsize JNICALL
|
jsize JNICALL
|
||||||
@ -1106,7 +1109,7 @@ NewGlobalRef(Thread* t, jobject o)
|
|||||||
ACQUIRE(t, t->m->referenceLock);
|
ACQUIRE(t, t->m->referenceLock);
|
||||||
|
|
||||||
if (o) {
|
if (o) {
|
||||||
Reference* r = new (t->m->system->allocate(sizeof(Reference)))
|
Reference* r = new (t->m->heap->allocate(t, sizeof(Reference), false))
|
||||||
Reference(*o, &(t->m->jniReferences));
|
Reference(*o, &(t->m->jniReferences));
|
||||||
|
|
||||||
return &(r->target);
|
return &(r->target);
|
||||||
@ -1251,7 +1254,7 @@ GetBooleanArrayElements(Thread* t, jbooleanArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = booleanArrayLength(t, *array) * sizeof(jboolean);
|
unsigned size = booleanArrayLength(t, *array) * sizeof(jboolean);
|
||||||
jboolean* p = static_cast<jboolean*>(t->m->system->allocate(size));
|
jboolean* p = static_cast<jboolean*>(t->m->heap->allocate(t, size, false));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &booleanArrayBody(t, *array, 0), size);
|
memcpy(p, &booleanArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1269,7 +1272,7 @@ GetByteArrayElements(Thread* t, jbyteArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = byteArrayLength(t, *array) * sizeof(jbyte);
|
unsigned size = byteArrayLength(t, *array) * sizeof(jbyte);
|
||||||
jbyte* p = static_cast<jbyte*>(t->m->system->allocate(size));
|
jbyte* p = static_cast<jbyte*>(t->m->heap->allocate(t, size, false));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &byteArrayBody(t, *array, 0), size);
|
memcpy(p, &byteArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1287,7 +1290,7 @@ GetCharArrayElements(Thread* t, jcharArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = charArrayLength(t, *array) * sizeof(jchar);
|
unsigned size = charArrayLength(t, *array) * sizeof(jchar);
|
||||||
jchar* p = static_cast<jchar*>(t->m->system->allocate(size));
|
jchar* p = static_cast<jchar*>(t->m->heap->allocate(t, size, false));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &charArrayBody(t, *array, 0), size);
|
memcpy(p, &charArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1305,7 +1308,7 @@ GetShortArrayElements(Thread* t, jshortArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = shortArrayLength(t, *array) * sizeof(jshort);
|
unsigned size = shortArrayLength(t, *array) * sizeof(jshort);
|
||||||
jshort* p = static_cast<jshort*>(t->m->system->allocate(size));
|
jshort* p = static_cast<jshort*>(t->m->heap->allocate(t, size, false));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &shortArrayBody(t, *array, 0), size);
|
memcpy(p, &shortArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1323,7 +1326,7 @@ GetIntArrayElements(Thread* t, jintArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = intArrayLength(t, *array) * sizeof(jint);
|
unsigned size = intArrayLength(t, *array) * sizeof(jint);
|
||||||
jint* p = static_cast<jint*>(t->m->system->allocate(size));
|
jint* p = static_cast<jint*>(t->m->heap->allocate(t, size, false));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &intArrayBody(t, *array, 0), size);
|
memcpy(p, &intArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1341,7 +1344,7 @@ GetLongArrayElements(Thread* t, jlongArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = longArrayLength(t, *array) * sizeof(jlong);
|
unsigned size = longArrayLength(t, *array) * sizeof(jlong);
|
||||||
jlong* p = static_cast<jlong*>(t->m->system->allocate(size));
|
jlong* p = static_cast<jlong*>(t->m->heap->allocate(t, size, false));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &longArrayBody(t, *array, 0), size);
|
memcpy(p, &longArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1359,7 +1362,7 @@ GetFloatArrayElements(Thread* t, jfloatArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = floatArrayLength(t, *array) * sizeof(jfloat);
|
unsigned size = floatArrayLength(t, *array) * sizeof(jfloat);
|
||||||
jfloat* p = static_cast<jfloat*>(t->m->system->allocate(size));
|
jfloat* p = static_cast<jfloat*>(t->m->heap->allocate(t, size, false));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &floatArrayBody(t, *array, 0), size);
|
memcpy(p, &floatArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1377,7 +1380,7 @@ GetDoubleArrayElements(Thread* t, jdoubleArray array, jboolean* isCopy)
|
|||||||
ENTER(t, Thread::ActiveState);
|
ENTER(t, Thread::ActiveState);
|
||||||
|
|
||||||
unsigned size = doubleArrayLength(t, *array) * sizeof(jdouble);
|
unsigned size = doubleArrayLength(t, *array) * sizeof(jdouble);
|
||||||
jdouble* p = static_cast<jdouble*>(t->m->system->allocate(size));
|
jdouble* p = static_cast<jdouble*>(t->m->heap->allocate(t, size, false));
|
||||||
if (size) {
|
if (size) {
|
||||||
memcpy(p, &doubleArrayBody(t, *array, 0), size);
|
memcpy(p, &doubleArrayBody(t, *array, 0), size);
|
||||||
}
|
}
|
||||||
@ -1404,7 +1407,7 @@ ReleaseBooleanArrayElements(Thread* t, jbooleanArray array, jboolean* p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->system->free(p, size);
|
t->m->heap->free(p, size, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1422,7 +1425,7 @@ ReleaseByteArrayElements(Thread* t, jbyteArray array, jbyte* p, jint mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->system->free(p, size);
|
t->m->heap->free(p, size, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1440,7 +1443,7 @@ ReleaseCharArrayElements(Thread* t, jcharArray array, jchar* p, jint mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->system->free(p, size);
|
t->m->heap->free(p, size, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1458,7 +1461,7 @@ ReleaseShortArrayElements(Thread* t, jshortArray array, jshort* p, jint mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->system->free(p, size);
|
t->m->heap->free(p, size, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1476,7 +1479,7 @@ ReleaseIntArrayElements(Thread* t, jintArray array, jint* p, jint mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->system->free(p, size);
|
t->m->heap->free(p, size, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1494,7 +1497,7 @@ ReleaseLongArrayElements(Thread* t, jlongArray array, jlong* p, jint mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->system->free(p, size);
|
t->m->heap->free(p, size, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1512,7 +1515,7 @@ ReleaseFloatArrayElements(Thread* t, jfloatArray array, jfloat* p, jint mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->system->free(p, size);
|
t->m->heap->free(p, size, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1531,7 +1534,7 @@ ReleaseDoubleArrayElements(Thread* t, jdoubleArray array, jdouble* p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mode == 0 or mode == JNI_ABORT) {
|
if (mode == 0 or mode == JNI_ABORT) {
|
||||||
t->m->system->free(p, size);
|
t->m->heap->free(p, size, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1980,7 +1983,8 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
|||||||
{
|
{
|
||||||
JDK1_1InitArgs* a = static_cast<JDK1_1InitArgs*>(args);
|
JDK1_1InitArgs* a = static_cast<JDK1_1InitArgs*>(args);
|
||||||
|
|
||||||
System* s = makeSystem(a->maxHeapSize);
|
System* s = makeSystem();
|
||||||
|
Heap* h = makeHeap(s, a->maxHeapSize);
|
||||||
|
|
||||||
unsigned size = sizeof(BUILTIN_CLASSPATH) + 1 + strlen(a->classpath);
|
unsigned size = sizeof(BUILTIN_CLASSPATH) + 1 + strlen(a->classpath);
|
||||||
char classpath[size];
|
char classpath[size];
|
||||||
@ -1988,9 +1992,9 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
|||||||
BUILTIN_CLASSPATH, s->pathSeparator(), a->classpath);
|
BUILTIN_CLASSPATH, s->pathSeparator(), a->classpath);
|
||||||
|
|
||||||
Finder* f = makeFinder(s, classpath);
|
Finder* f = makeFinder(s, classpath);
|
||||||
Processor* p = makeProcessor(s);
|
Processor* p = makeProcessor(s, h);
|
||||||
|
|
||||||
*m = new (s->allocate(sizeof(Machine))) Machine(s, f, p);
|
*m = new (h->allocate(0, sizeof(Machine), false)) Machine(s, h, f, p);
|
||||||
|
|
||||||
if (a->properties) {
|
if (a->properties) {
|
||||||
for (const char** p = a->properties; *p; ++p) {
|
for (const char** p = a->properties; *p; ++p) {
|
||||||
|
@ -482,9 +482,9 @@ void
|
|||||||
postCollect(Thread* t)
|
postCollect(Thread* t)
|
||||||
{
|
{
|
||||||
#ifdef VM_STRESS
|
#ifdef VM_STRESS
|
||||||
t->m->system->free(t->defaultHeap, Thread::HeapSizeInBytes);
|
t->allocator.free(t->defaultHeap, Thread::HeapSizeInBytes);
|
||||||
t->defaultHeap = static_cast<uintptr_t*>
|
t->defaultHeap = static_cast<uintptr_t*>
|
||||||
(t->m->system->allocate(Thread::HeapSizeInBytes));
|
(t->allocator.allocate(Thread::HeapSizeInBytes));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
t->heap = t->defaultHeap;
|
t->heap = t->defaultHeap;
|
||||||
@ -762,10 +762,11 @@ parsePool(Thread* t, Stream& s)
|
|||||||
unsigned count = s.read2() - 1;
|
unsigned count = s.read2() - 1;
|
||||||
|
|
||||||
object pool = makeSingleton(t, count);
|
object pool = makeSingleton(t, count);
|
||||||
|
PROTECT(t, pool);
|
||||||
|
|
||||||
if (count) {
|
if (count) {
|
||||||
uint32_t* index = static_cast<uint32_t*>
|
uint32_t* index = static_cast<uint32_t*>
|
||||||
(t->m->system->allocate(count * 4));
|
(t->m->heap->allocate(t, count * 4, false));
|
||||||
|
|
||||||
for (unsigned i = 0; i < count; ++i) {
|
for (unsigned i = 0; i < count; ++i) {
|
||||||
index[i] = s.position();
|
index[i] = s.position();
|
||||||
@ -807,13 +808,11 @@ parsePool(Thread* t, Stream& s)
|
|||||||
|
|
||||||
unsigned end = s.position();
|
unsigned end = s.position();
|
||||||
|
|
||||||
PROTECT(t, pool);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < count;) {
|
for (unsigned i = 0; i < count;) {
|
||||||
i += parsePoolEntry(t, s, index, pool, i);
|
i += parsePoolEntry(t, s, index, pool, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
t->m->system->free(index, count * 4);
|
t->m->heap->free(index, count * 4, false);
|
||||||
|
|
||||||
s.setPosition(end);
|
s.setPosition(end);
|
||||||
}
|
}
|
||||||
@ -1694,6 +1693,12 @@ class HeapClient: public Heap::Client {
|
|||||||
postVisit(m->rootThread, v);
|
postVisit(m->rootThread, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void collect(void* context, Heap::CollectionType type) {
|
||||||
|
Thread* t = static_cast<Thread*>(context);
|
||||||
|
ENTER(t, Thread::ExclusiveState);
|
||||||
|
collect(t, type);
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool isFixed(void* p) {
|
virtual bool isFixed(void* p) {
|
||||||
return objectFixed(m->rootThread, static_cast<object>(p));
|
return objectFixed(m->rootThread, static_cast<object>(p));
|
||||||
}
|
}
|
||||||
@ -1757,8 +1762,8 @@ class HeapClient: public Heap::Client {
|
|||||||
::walk(m->rootThread, w, o);
|
::walk(m->rootThread, w, o);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
void dispose() {
|
||||||
m->system->free(this, sizeof(*this));
|
m->heap->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -1769,11 +1774,13 @@ class HeapClient: public Heap::Client {
|
|||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
Machine::Machine(System* system, Finder* finder, Processor* processor):
|
Machine::Machine(System* system, Heap* heap, Finder* finder,
|
||||||
|
Processor* processor):
|
||||||
vtable(&javaVMVTable),
|
vtable(&javaVMVTable),
|
||||||
system(system),
|
system(system),
|
||||||
heap(makeHeap(system, new (system->allocate(sizeof(HeapClient)))
|
heapClient(new (heap->allocate(0, sizeof(HeapClient), false))
|
||||||
HeapClient(this))),
|
HeapClient(this)),
|
||||||
|
heap(heap),
|
||||||
finder(finder),
|
finder(finder),
|
||||||
processor(processor),
|
processor(processor),
|
||||||
rootThread(0),
|
rootThread(0),
|
||||||
@ -1803,6 +1810,8 @@ Machine::Machine(System* system, Finder* finder, Processor* processor):
|
|||||||
unsafe(false),
|
unsafe(false),
|
||||||
heapPoolIndex(0)
|
heapPoolIndex(0)
|
||||||
{
|
{
|
||||||
|
heap->setClient(heapClient);
|
||||||
|
|
||||||
populateJNITables(&javaVMVTable, &jniEnvVTable);
|
populateJNITables(&javaVMVTable, &jniEnvVTable);
|
||||||
|
|
||||||
if (not system->success(system->make(&localThread)) or
|
if (not system->success(system->make(&localThread)) or
|
||||||
@ -1830,18 +1839,18 @@ Machine::dispose()
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Reference* r = jniReferences; r;) {
|
for (Reference* r = jniReferences; r;) {
|
||||||
Reference* t = r;
|
Reference* tmp = r;
|
||||||
r = r->next;
|
r = r->next;
|
||||||
system->free(t, sizeof(*t));
|
heap->free(tmp, sizeof(*tmp), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < heapPoolIndex; ++i) {
|
for (unsigned i = 0; i < heapPoolIndex; ++i) {
|
||||||
system->free(heapPool[i], Thread::HeapSizeInBytes);
|
heap->free(heapPool[i], Thread::HeapSizeInBytes, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
heap->dispose();
|
static_cast<HeapClient*>(heapClient)->dispose();
|
||||||
|
|
||||||
system->free(this, sizeof(*this));
|
heap->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
||||||
@ -1859,7 +1868,8 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
|||||||
heapOffset(0),
|
heapOffset(0),
|
||||||
protector(0),
|
protector(0),
|
||||||
runnable(this),
|
runnable(this),
|
||||||
defaultHeap(static_cast<uintptr_t*>(m->system->allocate(HeapSizeInBytes))),
|
defaultHeap(static_cast<uintptr_t*>
|
||||||
|
(m->heap->allocate(parent, HeapSizeInBytes, false))),
|
||||||
heap(defaultHeap)
|
heap(defaultHeap)
|
||||||
#ifdef VM_STRESS
|
#ifdef VM_STRESS
|
||||||
, stress(false)
|
, stress(false)
|
||||||
@ -1996,7 +2006,7 @@ Thread::dispose()
|
|||||||
systemThread->dispose();
|
systemThread->dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
m->system->free(defaultHeap, Thread::HeapSizeInBytes);
|
m->heap->free(defaultHeap, Thread::HeapSizeInBytes, false);
|
||||||
|
|
||||||
m->processor->dispose(this);
|
m->processor->dispose(this);
|
||||||
}
|
}
|
||||||
@ -2145,15 +2155,15 @@ object
|
|||||||
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask)
|
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask)
|
||||||
{
|
{
|
||||||
return allocate3
|
return allocate3
|
||||||
(t, t->m->system,
|
(t, t->m->heap,
|
||||||
ceiling(sizeInBytes, BytesPerWord) > Thread::HeapSizeInWords ?
|
ceiling(sizeInBytes, BytesPerWord) > Thread::HeapSizeInWords ?
|
||||||
Machine::FixedAllocation : Machine::MovableAllocation,
|
Machine::FixedAllocation : Machine::MovableAllocation,
|
||||||
sizeInBytes, objectMask);
|
sizeInBytes, false, objectMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
||||||
unsigned sizeInBytes, bool objectMask)
|
unsigned sizeInBytes, bool executable, bool objectMask)
|
||||||
{
|
{
|
||||||
ACQUIRE_RAW(t, t->m->stateLock);
|
ACQUIRE_RAW(t, t->m->stateLock);
|
||||||
|
|
||||||
@ -2175,7 +2185,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
|||||||
t->heap = 0;
|
t->heap = 0;
|
||||||
if (t->m->heapPoolIndex < Machine::HeapPoolSize) {
|
if (t->m->heapPoolIndex < Machine::HeapPoolSize) {
|
||||||
t->heap = static_cast<uintptr_t*>
|
t->heap = static_cast<uintptr_t*>
|
||||||
(t->m->system->tryAllocate(Thread::HeapSizeInBytes));
|
(t->m->heap->tryAllocate(0, Thread::HeapSizeInBytes, false));
|
||||||
if (t->heap) {
|
if (t->heap) {
|
||||||
t->m->heapPool[t->m->heapPoolIndex++] = t->heap;
|
t->m->heapPool[t->m->heapPoolIndex++] = t->heap;
|
||||||
t->heapOffset += t->heapIndex;
|
t->heapOffset += t->heapIndex;
|
||||||
@ -2198,7 +2208,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
|||||||
unsigned total;
|
unsigned total;
|
||||||
object o = static_cast<object>
|
object o = static_cast<object>
|
||||||
(t->m->heap->allocateFixed
|
(t->m->heap->allocateFixed
|
||||||
(allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total));
|
(allocator, t, ceiling(sizeInBytes, BytesPerWord), objectMask, &total));
|
||||||
|
|
||||||
cast<uintptr_t>(o, 0) = FixedMark;
|
cast<uintptr_t>(o, 0) = FixedMark;
|
||||||
|
|
||||||
@ -2211,7 +2221,8 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
|||||||
unsigned total;
|
unsigned total;
|
||||||
object o = static_cast<object>
|
object o = static_cast<object>
|
||||||
(t->m->heap->allocateImmortal
|
(t->m->heap->allocateImmortal
|
||||||
(allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total));
|
(allocator, t, ceiling(sizeInBytes, BytesPerWord),
|
||||||
|
executable, objectMask, &total));
|
||||||
|
|
||||||
cast<uintptr_t>(o, 0) = FixedMark;
|
cast<uintptr_t>(o, 0) = FixedMark;
|
||||||
|
|
||||||
@ -2826,7 +2837,7 @@ collect(Thread* t, Heap::CollectionType type)
|
|||||||
killZombies(t, m->rootThread);
|
killZombies(t, m->rootThread);
|
||||||
|
|
||||||
for (unsigned i = 0; i < m->heapPoolIndex; ++i) {
|
for (unsigned i = 0; i < m->heapPoolIndex; ++i) {
|
||||||
m->system->free(m->heapPool[i], Thread::HeapSizeInBytes);
|
m->heap->free(m->heapPool[i], Thread::HeapSizeInBytes, false);
|
||||||
}
|
}
|
||||||
m->heapPoolIndex = 0;
|
m->heapPoolIndex = 0;
|
||||||
|
|
||||||
|
@ -1111,7 +1111,7 @@ class Machine {
|
|||||||
ImmortalAllocation
|
ImmortalAllocation
|
||||||
};
|
};
|
||||||
|
|
||||||
Machine(System* system, Finder* finder, Processor* processor);
|
Machine(System* system, Heap* heap, Finder* finder, Processor* processor);
|
||||||
|
|
||||||
~Machine() {
|
~Machine() {
|
||||||
dispose();
|
dispose();
|
||||||
@ -1125,6 +1125,7 @@ class Machine {
|
|||||||
|
|
||||||
JavaVMVTable* vtable;
|
JavaVMVTable* vtable;
|
||||||
System* system;
|
System* system;
|
||||||
|
Heap::Client* heapClient;
|
||||||
Heap* heap;
|
Heap* heap;
|
||||||
Finder* finder;
|
Finder* finder;
|
||||||
Processor* processor;
|
Processor* processor;
|
||||||
@ -1168,6 +1169,16 @@ threadInterrupted(Thread* t, object thread);
|
|||||||
void
|
void
|
||||||
enterActiveState(Thread* t);
|
enterActiveState(Thread* t);
|
||||||
|
|
||||||
|
#ifdef VM_STRESS
|
||||||
|
|
||||||
|
inline void stress(Thread* t);
|
||||||
|
|
||||||
|
#else // not VM_STRESS
|
||||||
|
|
||||||
|
#define stress(t)
|
||||||
|
|
||||||
|
#endif // not VM_STRESS
|
||||||
|
|
||||||
class Thread {
|
class Thread {
|
||||||
public:
|
public:
|
||||||
enum State {
|
enum State {
|
||||||
@ -1306,7 +1317,7 @@ dispose(Thread* t, Reference* r)
|
|||||||
if (r->next) {
|
if (r->next) {
|
||||||
r->next->handle = r->handle;
|
r->next->handle = r->handle;
|
||||||
}
|
}
|
||||||
t->m->system->free(r, sizeof(*r));
|
t->m->heap->free(r, sizeof(*r), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -1335,12 +1346,6 @@ stress(Thread* t)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // not VM_STRESS
|
|
||||||
|
|
||||||
inline void
|
|
||||||
stress(Thread*)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
#endif // not VM_STRESS
|
#endif // not VM_STRESS
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
@ -1415,7 +1420,7 @@ allocate2(Thread* t, unsigned sizeInBytes, bool objectMask);
|
|||||||
|
|
||||||
object
|
object
|
||||||
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
||||||
unsigned sizeInBytes, bool objectMask);
|
unsigned sizeInBytes, bool executable, bool objectMask);
|
||||||
|
|
||||||
inline object
|
inline object
|
||||||
allocateSmall(Thread* t, unsigned sizeInBytes)
|
allocateSmall(Thread* t, unsigned sizeInBytes)
|
||||||
|
184
src/posix.cpp
184
src/posix.cpp
@ -108,6 +108,14 @@ run(void* r)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
allocate(System* s, unsigned size)
|
||||||
|
{
|
||||||
|
void* p = s->tryAllocate(size, false);
|
||||||
|
if (p == 0) abort();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
const bool Verbose = false;
|
const bool Verbose = false;
|
||||||
|
|
||||||
const unsigned Waiting = 1 << 0;
|
const unsigned Waiting = 1 << 0;
|
||||||
@ -115,45 +123,6 @@ const unsigned Notified = 1 << 1;
|
|||||||
|
|
||||||
class MySystem: public System {
|
class MySystem: public System {
|
||||||
public:
|
public:
|
||||||
class CodeAllocator: public Allocator {
|
|
||||||
public:
|
|
||||||
CodeAllocator(MySystem* s): s(s) { }
|
|
||||||
|
|
||||||
virtual void* tryAllocate(unsigned size) {
|
|
||||||
assert(s, size % LikelyPageSizeInBytes == 0);
|
|
||||||
|
|
||||||
#ifdef __x86_64__
|
|
||||||
void* p = mmap(0, size, PROT_EXEC | PROT_READ | PROT_WRITE,
|
|
||||||
MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
|
|
||||||
|
|
||||||
if (p == MAP_FAILED) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return s->tryAllocate(size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void* allocate(unsigned size) {
|
|
||||||
void* p = tryAllocate(size);
|
|
||||||
expect(s, p);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void free(const void* p, unsigned size) {
|
|
||||||
#ifdef __x86_64__
|
|
||||||
int r UNUSED = munmap(const_cast<void*>(p), size);
|
|
||||||
assert(s, r == 0);
|
|
||||||
#else
|
|
||||||
s->free(p, size);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
MySystem* s;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Thread: public System::Thread {
|
class Thread: public System::Thread {
|
||||||
public:
|
public:
|
||||||
Thread(System* s, System::Runnable* r):
|
Thread(System* s, System::Runnable* r):
|
||||||
@ -182,7 +151,7 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
s->free(this, sizeof(*this));
|
s->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
@ -194,6 +163,29 @@ class MySystem: public System {
|
|||||||
unsigned flags;
|
unsigned flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Mutex: public System::Mutex {
|
||||||
|
public:
|
||||||
|
Mutex(System* s): s(s) {
|
||||||
|
pthread_mutex_init(&mutex, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void acquire() {
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void release() {
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void dispose() {
|
||||||
|
pthread_mutex_destroy(&mutex);
|
||||||
|
s->free(this, sizeof(*this), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
System* s;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
};
|
||||||
|
|
||||||
class Monitor: public System::Monitor {
|
class Monitor: public System::Monitor {
|
||||||
public:
|
public:
|
||||||
Monitor(System* s): s(s), owner_(0), first(0), last(0), depth(0) {
|
Monitor(System* s): s(s), owner_(0), first(0), last(0), depth(0) {
|
||||||
@ -377,7 +369,7 @@ class MySystem: public System {
|
|||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
expect(s, owner_ == 0);
|
expect(s, owner_ == 0);
|
||||||
pthread_mutex_destroy(&mutex);
|
pthread_mutex_destroy(&mutex);
|
||||||
s->free(this, sizeof(*this));
|
s->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -408,7 +400,7 @@ class MySystem: public System {
|
|||||||
int r UNUSED = pthread_key_delete(key);
|
int r UNUSED = pthread_key_delete(key);
|
||||||
expect(s, r == 0);
|
expect(s, r == 0);
|
||||||
|
|
||||||
s->free(this, sizeof(*this));
|
s->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -435,7 +427,7 @@ class MySystem: public System {
|
|||||||
if (start_) {
|
if (start_) {
|
||||||
munmap(start_, length_);
|
munmap(start_, length_);
|
||||||
}
|
}
|
||||||
s->free(this, sizeof(*this));
|
s->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -483,10 +475,10 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name_) {
|
if (name_) {
|
||||||
s->free(name_, nameLength + 1);
|
s->free(name_, nameLength + 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->free(this, sizeof(*this));
|
s->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -497,9 +489,7 @@ class MySystem: public System {
|
|||||||
System::Library* next_;
|
System::Library* next_;
|
||||||
};
|
};
|
||||||
|
|
||||||
MySystem(unsigned limit): limit(limit), count(0), codeAllocator_(this) {
|
MySystem() {
|
||||||
pthread_mutex_init(&mutex, 0);
|
|
||||||
|
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
memset(&sa, 0, sizeof(struct sigaction));
|
memset(&sa, 0, sizeof(struct sigaction));
|
||||||
sigemptyset(&(sa.sa_mask));
|
sigemptyset(&(sa.sa_mask));
|
||||||
@ -510,98 +500,65 @@ class MySystem: public System {
|
|||||||
expect(this, rv == 0);
|
expect(this, rv == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* tryAllocate(unsigned size) {
|
virtual void* tryAllocate(unsigned size, bool executable) {
|
||||||
ACQUIRE(mutex);
|
assert(this, (not executable) or (size % LikelyPageSizeInBytes == 0));
|
||||||
|
|
||||||
if (Verbose) {
|
if (executable) {
|
||||||
fprintf(stderr, "try %d; count: %d; limit: %d\n",
|
void* p = mmap(0, size, PROT_EXEC | PROT_READ | PROT_WRITE,
|
||||||
size, count, limit);
|
MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
|
||||||
}
|
|
||||||
|
|
||||||
if (count + size > limit) {
|
if (p == MAP_FAILED) {
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
uintptr_t* up = static_cast<uintptr_t*>
|
|
||||||
(malloc(size + sizeof(uintptr_t)));
|
|
||||||
if (up == 0) {
|
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
*up = size;
|
|
||||||
count += *up;
|
|
||||||
|
|
||||||
return up + 1;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void* p = malloc(size);
|
|
||||||
if (p == 0) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
count += size;
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
#endif
|
} else {
|
||||||
|
return malloc(size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void free(const void* p, unsigned size) {
|
virtual void free(const void* p, unsigned size, bool executable) {
|
||||||
ACQUIRE(mutex);
|
|
||||||
|
|
||||||
if (Verbose) {
|
|
||||||
fprintf(stderr, "free %d; count: %d; limit: %d\n",
|
|
||||||
size, count, limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p) {
|
if (p) {
|
||||||
#ifndef NDEBUG
|
if (executable) {
|
||||||
const uintptr_t* up = static_cast<const uintptr_t*>(p) - 1;
|
int r UNUSED = munmap(const_cast<void*>(p), size);
|
||||||
|
assert(this, r == 0);
|
||||||
if (*up != size) abort();
|
} else {
|
||||||
if (count < *up) abort();
|
::free(const_cast<void*>(p));
|
||||||
|
}
|
||||||
count -= *up;
|
|
||||||
|
|
||||||
::free(const_cast<uintptr_t*>(up));
|
|
||||||
#else
|
|
||||||
if (count < size) abort();
|
|
||||||
|
|
||||||
count -= size;
|
|
||||||
|
|
||||||
::free(const_cast<void*>(p));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Allocator* codeAllocator() {
|
|
||||||
return &codeAllocator_;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool success(Status s) {
|
virtual bool success(Status s) {
|
||||||
return s == 0;
|
return s == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Status attach(Runnable* r) {
|
virtual Status attach(Runnable* r) {
|
||||||
Thread* t = new (System::allocate(sizeof(Thread))) Thread(this, r);
|
Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r);
|
||||||
t->thread = pthread_self();
|
t->thread = pthread_self();
|
||||||
r->attach(t);
|
r->attach(t);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Status start(Runnable* r) {
|
virtual Status start(Runnable* r) {
|
||||||
Thread* t = new (System::allocate(sizeof(Thread))) Thread(this, r);
|
Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r);
|
||||||
r->attach(t);
|
r->attach(t);
|
||||||
int rv UNUSED = pthread_create(&(t->thread), 0, run, r);
|
int rv UNUSED = pthread_create(&(t->thread), 0, run, r);
|
||||||
expect(this, rv == 0);
|
expect(this, rv == 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Status make(System::Mutex** m) {
|
||||||
|
*m = new (allocate(this, sizeof(Mutex))) Mutex(this);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
virtual Status make(System::Monitor** m) {
|
virtual Status make(System::Monitor** m) {
|
||||||
*m = new (System::allocate(sizeof(Monitor))) Monitor(this);
|
*m = new (allocate(this, sizeof(Monitor))) Monitor(this);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Status make(System::Local** l) {
|
virtual Status make(System::Local** l) {
|
||||||
*l = new (System::allocate(sizeof(Local))) Local(this);
|
*l = new (allocate(this, sizeof(Local))) Local(this);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -640,7 +597,7 @@ class MySystem: public System {
|
|||||||
if (r != -1) {
|
if (r != -1) {
|
||||||
void* data = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
void* data = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||||
if (data) {
|
if (data) {
|
||||||
*region = new (allocate(sizeof(Region)))
|
*region = new (allocate(this, sizeof(Region)))
|
||||||
Region(this, static_cast<uint8_t*>(data), s.st_size);
|
Region(this, static_cast<uint8_t*>(data), s.st_size);
|
||||||
status = 0;
|
status = 0;
|
||||||
}
|
}
|
||||||
@ -690,13 +647,13 @@ class MySystem: public System {
|
|||||||
|
|
||||||
char* n;
|
char* n;
|
||||||
if (name) {
|
if (name) {
|
||||||
n = static_cast<char*>(System::allocate(nameLength + 1));
|
n = static_cast<char*>(allocate(this, nameLength + 1));
|
||||||
memcpy(n, name, nameLength + 1);
|
memcpy(n, name, nameLength + 1);
|
||||||
} else {
|
} else {
|
||||||
n = 0;
|
n = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*lib = new (System::allocate(sizeof(Library)))
|
*lib = new (allocate(this, sizeof(Library)))
|
||||||
Library(this, p, n, nameLength, mapName, next);
|
Library(this, p, n, nameLength, mapName, next);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
@ -725,15 +682,8 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
assert(this, count == 0);
|
|
||||||
pthread_mutex_destroy(&mutex);
|
|
||||||
::free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_t mutex;
|
|
||||||
unsigned limit;
|
|
||||||
unsigned count;
|
|
||||||
CodeAllocator codeAllocator_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -741,9 +691,9 @@ class MySystem: public System {
|
|||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
System*
|
System*
|
||||||
makeSystem(unsigned heapSize)
|
makeSystem()
|
||||||
{
|
{
|
||||||
return new (malloc(sizeof(MySystem))) MySystem(heapSize);
|
return new (malloc(sizeof(MySystem))) MySystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
@ -134,7 +134,7 @@ class Processor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Processor*
|
Processor*
|
||||||
makeProcessor(System* system);
|
makeProcessor(System* system, Allocator* allocator);
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
|
||||||
|
25
src/system.h
25
src/system.h
@ -2,11 +2,10 @@
|
|||||||
#define SYSTEM_H
|
#define SYSTEM_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "allocator.h"
|
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
class System: public Allocator {
|
class System {
|
||||||
public:
|
public:
|
||||||
typedef intptr_t Status;
|
typedef intptr_t Status;
|
||||||
|
|
||||||
@ -34,6 +33,14 @@ class System: public Allocator {
|
|||||||
virtual void setInterrupted(bool v) = 0;
|
virtual void setInterrupted(bool v) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Mutex {
|
||||||
|
public:
|
||||||
|
virtual ~Mutex() { }
|
||||||
|
virtual void acquire() = 0;
|
||||||
|
virtual void release() = 0;
|
||||||
|
virtual void dispose() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class Monitor {
|
class Monitor {
|
||||||
public:
|
public:
|
||||||
virtual ~Monitor() { }
|
virtual ~Monitor() { }
|
||||||
@ -83,10 +90,12 @@ class System: public Allocator {
|
|||||||
|
|
||||||
virtual ~System() { }
|
virtual ~System() { }
|
||||||
|
|
||||||
virtual Allocator* codeAllocator() = 0;
|
|
||||||
virtual bool success(Status) = 0;
|
virtual bool success(Status) = 0;
|
||||||
|
virtual void* tryAllocate(unsigned size, bool executable) = 0;
|
||||||
|
virtual void free(const void* p, unsigned size, bool executable) = 0;
|
||||||
virtual Status attach(Runnable*) = 0;
|
virtual Status attach(Runnable*) = 0;
|
||||||
virtual Status start(Runnable*) = 0;
|
virtual Status start(Runnable*) = 0;
|
||||||
|
virtual Status make(Mutex**) = 0;
|
||||||
virtual Status make(Monitor**) = 0;
|
virtual Status make(Monitor**) = 0;
|
||||||
virtual Status make(Local**) = 0;
|
virtual Status make(Local**) = 0;
|
||||||
virtual Status handleSegFault(SignalHandler* handler) = 0;
|
virtual Status handleSegFault(SignalHandler* handler) = 0;
|
||||||
@ -102,14 +111,6 @@ class System: public Allocator {
|
|||||||
virtual void exit(int code) = 0;
|
virtual void exit(int code) = 0;
|
||||||
virtual void abort() = 0;
|
virtual void abort() = 0;
|
||||||
virtual void dispose() = 0;
|
virtual void dispose() = 0;
|
||||||
|
|
||||||
virtual void* allocate(unsigned size) {
|
|
||||||
void* p = tryAllocate(size);
|
|
||||||
if (p == 0) {
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline void NO_RETURN
|
inline void NO_RETURN
|
||||||
@ -146,7 +147,7 @@ assert(System* s, bool v)
|
|||||||
#endif // not NDEBUG
|
#endif // not NDEBUG
|
||||||
|
|
||||||
System*
|
System*
|
||||||
makeSystem(unsigned heapSize);
|
makeSystem();
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
|
||||||
|
14
src/vector.h
14
src/vector.h
@ -7,8 +7,11 @@ namespace vm {
|
|||||||
|
|
||||||
class Vector {
|
class Vector {
|
||||||
public:
|
public:
|
||||||
Vector(System* s, unsigned minimumCapacity):
|
Vector(System* s, Allocator* allocator, void* context,
|
||||||
|
unsigned minimumCapacity):
|
||||||
s(s),
|
s(s),
|
||||||
|
allocator(allocator),
|
||||||
|
context(context),
|
||||||
data(0),
|
data(0),
|
||||||
position(0),
|
position(0),
|
||||||
capacity(0),
|
capacity(0),
|
||||||
@ -21,7 +24,7 @@ class Vector {
|
|||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
if (data and minimumCapacity >= 0) {
|
if (data and minimumCapacity >= 0) {
|
||||||
s->free(data, capacity);
|
allocator->free(data, capacity, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,10 +43,11 @@ class Vector {
|
|||||||
|
|
||||||
unsigned newCapacity = max
|
unsigned newCapacity = max
|
||||||
(position + space, max(minimumCapacity, capacity * 2));
|
(position + space, max(minimumCapacity, capacity * 2));
|
||||||
uint8_t* newData = static_cast<uint8_t*>(s->allocate(newCapacity));
|
uint8_t* newData = static_cast<uint8_t*>
|
||||||
|
(allocator->allocate(context, newCapacity, false));
|
||||||
if (data) {
|
if (data) {
|
||||||
memcpy(newData, data, position);
|
memcpy(newData, data, position);
|
||||||
s->free(data, capacity);
|
allocator->free(data, capacity, false);
|
||||||
}
|
}
|
||||||
data = newData;
|
data = newData;
|
||||||
capacity = newCapacity;
|
capacity = newCapacity;
|
||||||
@ -129,6 +133,8 @@ class Vector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
|
Allocator* allocator;
|
||||||
|
void* context;
|
||||||
uint8_t* data;
|
uint8_t* data;
|
||||||
unsigned position;
|
unsigned position;
|
||||||
unsigned capacity;
|
unsigned capacity;
|
||||||
|
140
src/windows.cpp
140
src/windows.cpp
@ -57,6 +57,14 @@ run(void* r)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
allocate(System* s, unsigned size)
|
||||||
|
{
|
||||||
|
void* p = s->tryAllocate(size, false);
|
||||||
|
if (p == 0) abort();
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
const bool Verbose = false;
|
const bool Verbose = false;
|
||||||
|
|
||||||
const unsigned Waiting = 1 << 0;
|
const unsigned Waiting = 1 << 0;
|
||||||
@ -99,7 +107,7 @@ class MySystem: public System {
|
|||||||
CloseHandle(event);
|
CloseHandle(event);
|
||||||
CloseHandle(mutex);
|
CloseHandle(mutex);
|
||||||
CloseHandle(thread);
|
CloseHandle(thread);
|
||||||
s->free(this, sizeof(*this));
|
s->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE thread;
|
HANDLE thread;
|
||||||
@ -111,6 +119,32 @@ class MySystem: public System {
|
|||||||
unsigned flags;
|
unsigned flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Mutex: public System::Mutex {
|
||||||
|
public:
|
||||||
|
Mutex(System* s): s(s) {
|
||||||
|
mutex = CreateMutex(0, false, 0);
|
||||||
|
assert(s, mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void acquire() {
|
||||||
|
int r UNUSED = WaitForSingleObject(mutex, INFINITE);
|
||||||
|
assert(s, r == WAIT_OBJECT_0);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void release() {
|
||||||
|
bool success UNUSED = ReleaseMutex(mutex);
|
||||||
|
assert(s, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void dispose() {
|
||||||
|
CloseHandle(mutex);
|
||||||
|
s->free(this, sizeof(*this), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
System* s;
|
||||||
|
HANDLE mutex;
|
||||||
|
};
|
||||||
|
|
||||||
class Monitor: public System::Monitor {
|
class Monitor: public System::Monitor {
|
||||||
public:
|
public:
|
||||||
Monitor(System* s): s(s), owner_(0), first(0), last(0), depth(0) {
|
Monitor(System* s): s(s), owner_(0), first(0), last(0), depth(0) {
|
||||||
@ -309,7 +343,7 @@ class MySystem: public System {
|
|||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
assert(s, owner_ == 0);
|
assert(s, owner_ == 0);
|
||||||
CloseHandle(mutex);
|
CloseHandle(mutex);
|
||||||
s->free(this, sizeof(*this));
|
s->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -340,7 +374,7 @@ class MySystem: public System {
|
|||||||
bool r UNUSED = TlsFree(key);
|
bool r UNUSED = TlsFree(key);
|
||||||
assert(s, r);
|
assert(s, r);
|
||||||
|
|
||||||
s->free(this, sizeof(*this));
|
s->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -372,7 +406,7 @@ class MySystem: public System {
|
|||||||
if (mapping) CloseHandle(mapping);
|
if (mapping) CloseHandle(mapping);
|
||||||
if (file) CloseHandle(file);
|
if (file) CloseHandle(file);
|
||||||
}
|
}
|
||||||
system->free(this, sizeof(*this));
|
system->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* system;
|
System* system;
|
||||||
@ -428,10 +462,10 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name_) {
|
if (name_) {
|
||||||
s->free(name_, nameLength+1);
|
s->free(name_, nameLength + 1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
s->free(this, sizeof(*this));
|
s->free(this, sizeof(*this), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
@ -442,75 +476,17 @@ class MySystem: public System {
|
|||||||
System::Library* next_;
|
System::Library* next_;
|
||||||
};
|
};
|
||||||
|
|
||||||
MySystem(unsigned limit): limit(limit), count(0) {
|
MySystem() {
|
||||||
mutex = CreateMutex(0, false, 0);
|
mutex = CreateMutex(0, false, 0);
|
||||||
assert(this, mutex);
|
assert(this, mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* tryAllocate(unsigned size) {
|
virtual void* tryAllocate(unsigned size, bool) {
|
||||||
ACQUIRE(this, mutex);
|
return malloc(size);
|
||||||
|
|
||||||
if (Verbose) {
|
|
||||||
fprintf(stderr, "try %d; count: %d; limit: %d\n",
|
|
||||||
size, count, limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count + size > limit) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
uintptr_t* up = static_cast<uintptr_t*>
|
|
||||||
(malloc(size + sizeof(uintptr_t)));
|
|
||||||
if (up == 0) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
*up = size;
|
|
||||||
count += *up;
|
|
||||||
|
|
||||||
return up + 1;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void* p = malloc(size);
|
|
||||||
if (p == 0) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
count += size;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void free(const void* p, unsigned size) {
|
virtual void free(const void* p, unsigned, bool) {
|
||||||
ACQUIRE(this, mutex);
|
if (p) ::free(const_cast<void*>(p));
|
||||||
|
|
||||||
if (Verbose) {
|
|
||||||
fprintf(stderr, "free %d; count: %d; limit: %d\n",
|
|
||||||
size, count, limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
const uintptr_t* up = static_cast<const uintptr_t*>(p) - 1;
|
|
||||||
|
|
||||||
if (*up != size) abort();
|
|
||||||
if (count < *up) abort();
|
|
||||||
|
|
||||||
count -= *up;
|
|
||||||
|
|
||||||
::free(const_cast<uintptr_t*>(up));
|
|
||||||
#else
|
|
||||||
if (count < size) abort();
|
|
||||||
|
|
||||||
count -= size;
|
|
||||||
|
|
||||||
::free(const_cast<void*>(p));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Allocator* codeAllocator() {
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool success(Status s) {
|
virtual bool success(Status s) {
|
||||||
@ -518,7 +494,7 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual Status attach(Runnable* r) {
|
virtual Status attach(Runnable* r) {
|
||||||
Thread* t = new (System::allocate(sizeof(Thread))) Thread(this, r);
|
Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r);
|
||||||
bool success UNUSED = DuplicateHandle
|
bool success UNUSED = DuplicateHandle
|
||||||
(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
|
(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
|
||||||
&(t->thread), 0, false, DUPLICATE_SAME_ACCESS);
|
&(t->thread), 0, false, DUPLICATE_SAME_ACCESS);
|
||||||
@ -528,7 +504,7 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual Status start(Runnable* r) {
|
virtual Status start(Runnable* r) {
|
||||||
Thread* t = new (System::allocate(sizeof(Thread))) Thread(this, r);
|
Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r);
|
||||||
r->attach(t);
|
r->attach(t);
|
||||||
DWORD id;
|
DWORD id;
|
||||||
t->thread = CreateThread(0, 0, run, r, 0, &id);
|
t->thread = CreateThread(0, 0, run, r, 0, &id);
|
||||||
@ -536,13 +512,18 @@ class MySystem: public System {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual Status make(System::Mutex** m) {
|
||||||
|
*m = new (allocate(this, sizeof(Mutex))) Mutex(this);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
virtual Status make(System::Monitor** m) {
|
virtual Status make(System::Monitor** m) {
|
||||||
*m = new (System::allocate(sizeof(Monitor))) Monitor(this);
|
*m = new (allocate(this, sizeof(Monitor))) Monitor(this);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Status make(System::Local** l) {
|
virtual Status make(System::Local** l) {
|
||||||
*l = new (System::allocate(sizeof(Local))) Local(this);
|
*l = new (allocate(this, sizeof(Local))) Local(this);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -579,7 +560,7 @@ class MySystem: public System {
|
|||||||
if (mapping) {
|
if (mapping) {
|
||||||
void* data = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
|
void* data = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, 0);
|
||||||
if (data) {
|
if (data) {
|
||||||
*region = new (allocate(sizeof(Region)))
|
*region = new (allocate(this, sizeof(Region)))
|
||||||
Region(this, static_cast<uint8_t*>(data), size, file, mapping);
|
Region(this, static_cast<uint8_t*>(data), size, file, mapping);
|
||||||
status = 0;
|
status = 0;
|
||||||
}
|
}
|
||||||
@ -639,13 +620,13 @@ class MySystem: public System {
|
|||||||
|
|
||||||
char* n;
|
char* n;
|
||||||
if (name) {
|
if (name) {
|
||||||
n = static_cast<char*>(System::allocate(nameLength + 1));
|
n = static_cast<char*>(allocate(this, nameLength + 1));
|
||||||
memcpy(n, name, nameLength + 1);
|
memcpy(n, name, nameLength + 1);
|
||||||
} else {
|
} else {
|
||||||
n = 0;
|
n = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
*lib = new (System::allocate(sizeof(Library)))
|
*lib = new (allocate(this, sizeof(Library)))
|
||||||
Library(this, handle, n, mapName, nameLength, next);
|
Library(this, handle, n, mapName, nameLength, next);
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
@ -688,14 +669,11 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
assert(this, count == 0);
|
|
||||||
CloseHandle(mutex);
|
CloseHandle(mutex);
|
||||||
::free(this);
|
::free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE mutex;
|
HANDLE mutex;
|
||||||
unsigned limit;
|
|
||||||
unsigned count;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -703,9 +681,9 @@ class MySystem: public System {
|
|||||||
namespace vm {
|
namespace vm {
|
||||||
|
|
||||||
System*
|
System*
|
||||||
makeSystem(unsigned heapSize)
|
makeSystem()
|
||||||
{
|
{
|
||||||
return new (malloc(sizeof(MySystem))) MySystem(heapSize);
|
return new (malloc(sizeof(MySystem))) MySystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace vm
|
} // namespace vm
|
||||||
|
37
src/zone.h
37
src/zone.h
@ -17,9 +17,12 @@ class Zone: public Allocator {
|
|||||||
uint8_t data[0];
|
uint8_t data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
Zone(System* s, Allocator* a, unsigned minimumFootprint):
|
Zone(System* s, Allocator* allocator, void* context, bool executable,
|
||||||
|
unsigned minimumFootprint):
|
||||||
s(s),
|
s(s),
|
||||||
a(a),
|
allocator(allocator),
|
||||||
|
context(context),
|
||||||
|
executable(executable),
|
||||||
segment(0),
|
segment(0),
|
||||||
position(0),
|
position(0),
|
||||||
minimumFootprint(minimumFootprint < sizeof(Segment) ? 0 :
|
minimumFootprint(minimumFootprint < sizeof(Segment) ? 0 :
|
||||||
@ -33,11 +36,11 @@ class Zone: public Allocator {
|
|||||||
void dispose() {
|
void dispose() {
|
||||||
for (Segment* seg = segment, *next; seg; seg = next) {
|
for (Segment* seg = segment, *next; seg; seg = next) {
|
||||||
next = seg->next;
|
next = seg->next;
|
||||||
a->free(seg, sizeof(Segment) + seg->size);
|
allocator->free(seg, sizeof(Segment) + seg->size, executable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ensure(unsigned space) {
|
bool ensure(void* context, unsigned space, bool executable) {
|
||||||
if (segment == 0 or position + space > segment->size) {
|
if (segment == 0 or position + space > segment->size) {
|
||||||
unsigned size = max
|
unsigned size = max
|
||||||
(space, max
|
(space, max
|
||||||
@ -48,10 +51,10 @@ class Zone: public Allocator {
|
|||||||
size = (size + (LikelyPageSizeInBytes - 1))
|
size = (size + (LikelyPageSizeInBytes - 1))
|
||||||
& ~(LikelyPageSizeInBytes - 1);
|
& ~(LikelyPageSizeInBytes - 1);
|
||||||
|
|
||||||
void* p = a->tryAllocate(size);
|
void* p = allocator->tryAllocate(context, size, executable);
|
||||||
if (p == 0) {
|
if (p == 0) {
|
||||||
size = space + sizeof(Segment);
|
size = space + sizeof(Segment);
|
||||||
void* p = a->tryAllocate(size);
|
void* p = allocator->tryAllocate(context, size, executable);
|
||||||
if (p == 0) {
|
if (p == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -63,9 +66,11 @@ class Zone: public Allocator {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* tryAllocate(unsigned size) {
|
virtual void* tryAllocate(void* context, unsigned size, bool executable) {
|
||||||
|
assert(s, executable == this->executable);
|
||||||
|
|
||||||
size = pad(size);
|
size = pad(size);
|
||||||
if (ensure(size)) {
|
if (ensure(context, size, executable)) {
|
||||||
void* r = segment->data + position;
|
void* r = segment->data + position;
|
||||||
position += size;
|
position += size;
|
||||||
return r;
|
return r;
|
||||||
@ -74,19 +79,27 @@ class Zone: public Allocator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* allocate(unsigned size) {
|
virtual void* allocate(void* context, unsigned size, bool executable) {
|
||||||
void* p = tryAllocate(size);
|
assert(s, executable == this->executable);
|
||||||
|
|
||||||
|
void* p = tryAllocate(context, size, executable);
|
||||||
expect(s, p);
|
expect(s, p);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void free(const void*, unsigned) {
|
virtual void free(const void*, unsigned, bool) {
|
||||||
// not supported
|
// not supported
|
||||||
abort(s);
|
abort(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* allocate(unsigned size) {
|
||||||
|
return allocate(context, size, executable);
|
||||||
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
Allocator* a;
|
Allocator* allocator;
|
||||||
|
void* context;
|
||||||
|
bool executable;
|
||||||
Segment* segment;
|
Segment* segment;
|
||||||
unsigned position;
|
unsigned position;
|
||||||
unsigned minimumFootprint;
|
unsigned minimumFootprint;
|
||||||
|
Loading…
Reference in New Issue
Block a user