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