diff --git a/src/heap.cpp b/src/heap.cpp index d60b8bf8e8..c00f7043f4 100644 --- a/src/heap.cpp +++ b/src/heap.cpp @@ -707,48 +707,42 @@ bitset(Context* c, object o) } inline object -copyTo(Context* c, Segment* s, object o) +copyTo(Context* c, Segment* s, object o, unsigned size) { - class Allocator: public Heap::Allocator { - public: - Allocator(Segment* s): s(s) { } + if (s->remaining() < size) { + s->ensure(size); - virtual void* allocate(unsigned size) { - if (s->remaining() < size) { - s->ensure(size); - - if (Verbose) { - if (s == &(c->gen2)) { - fprintf(stderr, "grow gen2 to %d bytes\n", - c->gen2.capacity() * BytesPerWord); - } else if (s == &(c->nextGen1)) { - fprintf(stderr, "grow nextGen1 to %d bytes\n", - c->nextGen1.capacity() * BytesPerWord); - } else if (s == &(c->nextGen2)) { - fprintf(stderr, "grow nextGen2 to %d bytes\n", - c->nextGen2.capacity() * BytesPerWord); - } else { - abort(c); - } - } + if (Verbose) { + if (s == &(c->gen2)) { + fprintf(stderr, "grow gen2 to %d bytes\n", + c->gen2.capacity() * BytesPerWord); + } else if (s == &(c->nextGen1)) { + fprintf(stderr, "grow nextGen1 to %d bytes\n", + c->nextGen1.capacity() * BytesPerWord); + } else if (s == &(c->nextGen2)) { + fprintf(stderr, "grow nextGen2 to %d bytes\n", + c->nextGen2.capacity() * BytesPerWord); + } else { + abort(c); } - - return s->allocate(size); } - } allocator(s); - - c->client->copy(o, &allocator); - return p; + } + + object dst = s->allocate(size); + c->client->copy(o, dst); + return dst; } object copy2(Context* c, object o) { + unsigned size = c->client->copiedSizeInWords(o); + if (c->gen2.contains(o)) { assert(c, c->mode == MajorCollection or c->mode == Gen2Collection); - return copyTo(c, &(c->nextGen2), o); + return copyTo(c, &(c->nextGen2), o, size); } else if (c->gen1.contains(o)) { unsigned age = c->ageMap.get(o); if (age == TenureThreshold) { @@ -760,7 +754,7 @@ copy2(Context* c, object o) c->gen2Base = c->gen2.position(); } - return copyTo(c, &(c->gen2), o); + return copyTo(c, &(c->gen2), o, size); } else { if (Verbose) { fprintf(stderr, "overflow collection\n"); @@ -768,13 +762,13 @@ copy2(Context* c, object o) c->mode = OverflowCollection; initNextGen2(c); - return copyTo(c, &(c->nextGen2), o); + return copyTo(c, &(c->nextGen2), o, size); } } else { - return copyTo(c, &(c->nextGen2), o); + return copyTo(c, &(c->nextGen2), o, size); } } else { - o = copyTo(c, &(c->nextGen1), o); + o = copyTo(c, &(c->nextGen1), o, size); c->nextAgeMap.setOnly(o, age + 1); return o; } @@ -782,7 +776,7 @@ copy2(Context* c, object o) assert(c, not c->nextGen1.contains(o)); assert(c, not c->nextGen2.contains(o)); - o = copyTo(c, &(c->nextGen1), o); + o = copyTo(c, &(c->nextGen1), o, size); c->nextAgeMap.clear(o); diff --git a/src/heap.h b/src/heap.h index c6ce28f9de..4efe8ec5ca 100644 --- a/src/heap.h +++ b/src/heap.h @@ -24,18 +24,13 @@ class Heap { virtual bool visit(unsigned) = 0; }; - class Allocator { - public: - virtual ~Allocator() { } - virtual void* allocate(unsigned sizeInWords) = 0; - }; - class Client { public: virtual ~Client() { } virtual void visitRoots(Visitor*) = 0; virtual unsigned sizeInWords(void*) = 0; - virtual void copy(void*, Allocator*) = 0; + virtual unsigned copiedSizeInWords(void*) = 0; + virtual void copy(void*, void*) = 0; virtual void walk(void*, Walker*) = 0; }; diff --git a/src/types.def b/src/types.def index 1cde38c649..f528edfe28 100644 --- a/src/types.def +++ b/src/types.def @@ -93,6 +93,11 @@ (object second) (object third)) +(type finalizer + (object target) + (void* finalize) + (object next)) + (type hashMap (uint32_t size) (object array)) diff --git a/src/vm.cpp b/src/vm.cpp index 0663207a6f..ad112a0c56 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -25,8 +25,6 @@ const bool Debug = false; const uintptr_t HashTakenMark = 1; const uintptr_t ExtendedMark = 2; -const uintptr_t MonitorFlag -= static_cast(1) << ((BytesPerWord * 8) - 1); class Thread; @@ -81,13 +79,15 @@ class Machine { System::Monitor* stateLock; System::Monitor* heapLock; System::Monitor* classLock; - System::Monitor* monitorMapLock; + System::Monitor* finalizerLock; System::Library* libraries; object classMap; object bootstrapClassMap; object builtinMap; object monitorMap; object types; + object finalizers; + object doomed; bool unsafe; JNIEnvVTable jniEnvVTable; }; @@ -271,30 +271,7 @@ baseSize(Thread* t, object o, object class_) unsigned extendedSize(Thread* t, object o, unsigned baseSize) { - unsigned n = baseSize; - - if (objectExtended(t, o)) { - if (extendedWord(t, o, n) & MonitorFlag) { - n += BytesPerWord; - } - n += BytesPerWord; - } - - return n; -} - -inline bool -monitorAttached(Thread* t, object o, unsigned baseSize) -{ - return objectExtended(t, o) - and (extendedWord(t, o, baseSize) & MonitorFlag); -} - -inline System::Monitor*& -attachedMonitor(Thread* t, object o, unsigned baseSize) -{ - assert(t, monitorAttached(t, o, baseSize)); - return cast(o, (baseSize + 1) * BytesPerWord); + return baseSize + objectExtended(t, o); } inline bool @@ -320,7 +297,7 @@ inline uint32_t objectHash(Thread* t, object o) { if (objectExtended(t, o)) { - return extendedWord(t, o, baseSize(t, o, objectClass(o))) & PointerMask; + return extendedWord(t, o, baseSize(t, o, objectClass(t, o))); } else { markHashTaken(t, o); return takeHash(t, o); @@ -402,7 +379,8 @@ hashMapFind(Thread* t, object map, object key, } void -hashMapGrow(Thread* t, object map, uint32_t (*hash)(Thread*, object)) +hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object), + unsigned size) { PROTECT(t, map); @@ -410,7 +388,7 @@ hashMapGrow(Thread* t, object map, uint32_t (*hash)(Thread*, object)) unsigned oldLength = (oldArray ? arrayLength(t, oldArray) : 0); PROTECT(t, oldArray); - unsigned newLength = (oldLength ? oldLength * 2 : 32); + unsigned newLength = max(nextPowerOfTwo(size), 16); object newArray = makeArray(t, newLength, true); if (oldArray) { @@ -446,7 +424,7 @@ hashMapInsert(Thread* t, object map, object key, object value, PROTECT(t, key); PROTECT(t, value); - hashMapGrow(t, map, hash); + hashMapResize(t, map, hash, arrayLength(t, array) * 2); array = hashMapArray(t, map); } @@ -458,6 +436,39 @@ hashMapInsert(Thread* t, object map, object key, object value, set(t, arrayBody(t, array, index), n); } +object +hashMapRemove(Thread* t, object map, object key, + uint32_t (*hash)(Thread*, object), + bool (*equal)(Thread*, object, object)) +{ + object array = hashMapArray(t, map); + object o = 0; + if (array) { + unsigned index = hash(t, key) & (arrayLength(t, array) - 1); + object n = arrayBody(t, array, index); + object p = 0; + while (n) { + if (equal(t, tripleFirst(t, n), key)) { + o = tripleFirst(t, n); + if (p) { + set(t, tripleThird(t, p), tripleThird(t, n)); + } else { + set(t, arrayBody(t, array, index), tripleThird(t, n)); + } + } + + p = n; + n = tripleThird(t, n); + } + } + + if (hashMapSize(t, map) <= arrayLength(t, array) / 3) { + hashMapResize(t, map, hash, arrayLength(t, array) / 2); + } + + return o; +} + object hashMapIterator(Thread* t, object map) { @@ -594,6 +605,28 @@ collect(Machine* m, Heap::CollectionType type) for (Thread* t = m->rootThread; t; t = t->next) { ::visitRoots(t, v); } + + Thread* t = m->rootThread; + for (object* f = &(m->finalizers); *f;) { + object o = finalizerTarget(t, *f); + if (m->heap->follow(o) == o) { + // object has not been collected + object x = *f; + *f = finalizerNext(t, x); + finalizerNext(t, x) = m->doomed; + m->doomed = x; + } else { + f = &finalizerNext(t, *f); + } + } + + for (object* f = &(m->finalizers); *f; f = &finalizerNext(t, *f)) { + v->visit(f); + } + + for (object* f = &(m->doomed); *f; f = &finalizerNext(t, *f)) { + v->visit(f); + } } virtual unsigned sizeInWords(object o) { @@ -605,55 +638,35 @@ collect(Machine* m, Heap::CollectionType type) (t, o, baseSize(t, o, m->heap->follow(objectClass(t, o)))); } - virtual void copy(object o, Heap::Allocator* allocator) { + virtual unsigned copiedSizeInWords(object o) { + Thread* t = m->rootThread; + + o = m->heap->follow(mask(o)); + + unsigned n = baseSize(t, o, m->heap->follow(objectClass(t, o))); + + if (objectExtended(t, o) or hashTaken(t, o)) { + ++ n; + } + + return n; + } + + virtual void copy(object o, object dst) { Thread* t = m->rootThread; o = m->heap->follow(mask(o)); unsigned base = baseSize(t, o, m->heap->follow(objectClass(t, o))); - unsigned copyCount = base; - unsigned allocateCount = base; + unsigned n = extendedSize(t, o, base); - System::Monitor* monitor = 0; - - if (objectExtended(t, o)) { - copyCount += BytesPerWord; - allocateCount += BytesPerWord; - - if (extendedWord(t, o, base) & MonitorFlag) { - copyCount += BytesPerWord; - allocateCount += BytesPerWord; - } else { - monitor = gcHashMapRemove - (t, m->monitorMap, o, gcObjectHash, gcObjectEqual); - - if (monitor) { - allocateCount += BytesPerWord; - } - } - } else if (hashTaken(t, o)) { - allocateCount += BytesPerWord; - - monitor = gcHashMapRemove - (t, m->monitorMap, o, gcObjectHash, gcObjectEqual); - - if (monitor) { - allocateCount += BytesPerWord; - } - } - - object dst = allocator->allocate(allocateCount); - memcpy(o, dst, copyCount * BytesPerWord); + memcpy(o, dst, n * BytesPerWord); if (hashTaken(t, o)) { extendedWord(t, dst, base) = takeHash(t, o); cast(dst, 0) &= PointerMask; cast(dst, 0) |= ExtendedMark; } - - if (monitor) { - attachedMonitor(t, dst, base) = monitor; - } } virtual void walk(void* p, Heap::Walker* w) { @@ -730,6 +743,13 @@ collect(Machine* m, Heap::CollectionType type) m->unsafe = false; postCollect(m->rootThread); + + Thread* t = m->rootThread; + for (object f = m->doomed; f; f = tripleThird(t, f)) { + reinterpret_cast(finalizerFinalize(t, f)) + (t, finalizerTarget(t, f)); + } + m->doomed = 0; } void @@ -913,39 +933,48 @@ make(Thread* t, object class_) return instance; } -System::Monitor* -mappedMonitor(Thread* t, object o) +void +addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object)) { - PROTECT(t, o); + PROTECT(t, target); - ACQUIRE(t, t->vm->monitorMapLock); + ACQUIRE(t, t->vm->finalizerLock); + object p = makePointer(t, reinterpret_cast(finalize)); + t->vm->finalizers = makeTriple(t, target, p, t->vm->finalizers); +} + +void +removeMonitor(Thread* t, object o) +{ + hashMapRemove(t, t->vm->monitorMap, o, objectHash, objectEqual); +} + +System::Monitor* +objectMonitor(Thread* t, object o) +{ object p = hashMapFind(t, t->vm->monitorMap, o, objectHash, objectEqual); if (p) { return static_cast(pointerValue(t, p)); } else { + PROTECT(t, o); + + ENTER(t, Thread::ExclusiveState); + + System::Monitor* m; System::Status s = t->vm->system->make(&m); expect(t, t->vm->system->success(s)); - object pointer = makePointer(t, m); - hashMapInsert(t, t->vm->monitorMap, o, pointer, objectHash); + p = makePointer(t, m); + hashMapInsert(t, t->vm->monitorMap, o, p, objectHash); + + addFinalizer(t, o, removeMonitor); return m; } } -inline System::Monitor* -objectMonitor(Thread* t, object o) -{ - unsigned base = baseSize(t, o); - if (monitorAttached(t, o, base)) { - return attachedMonitor(t, o, base); - } else { - return mappedMonitor(t, o); - } -} - object makeByteArray(Thread* t, const char* format, va_list a) { @@ -2167,7 +2196,10 @@ updateBootstrapClass(Thread* t, object bootstrapClass, object class_) ENTER(t, Thread::ExclusiveState); - memcpy(bootstrapClass, class_, extendedSize(t, class_) * BytesPerWord); + memcpy(bootstrapClass, + class_, + extendedSize(t, class_, baseSize(t, class_, objectClass(t, class_))) + * BytesPerWord); object fieldTable = classFieldTable(t, class_); if (fieldTable) { @@ -2471,7 +2503,7 @@ invokeNative(Thread* t, object method) } } -object +object& frameLocals(Thread* t, object frame, unsigned index) { return t->stack[frameStackBase(t, frame) + index]; @@ -2608,13 +2640,15 @@ Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder): stateLock(0), heapLock(0), classLock(0), - monitorMapLock(0), + finalizerLock(0), libraries(0), classMap(0), bootstrapClassMap(0), builtinMap(0), monitorMap(0), types(0), + finalizers(0), + doomed(0), unsafe(false) { memset(&jniEnvVTable, 0, sizeof(JNIEnvVTable)); @@ -2626,7 +2660,7 @@ Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder): if (not system->success(system->make(&stateLock)) or not system->success(system->make(&heapLock)) or not system->success(system->make(&classLock)) or - not system->success(system->make(&monitorMapLock))) + not system->success(system->make(&finalizerLock))) { system->abort(); } @@ -2638,6 +2672,8 @@ Machine::dispose() stateLock->dispose(); heapLock->dispose(); classLock->dispose(); + finalizerLock->dispose(); + if (libraries) { libraries->dispose(); }