corda/src/machine.cpp

918 lines
20 KiB
C++
Raw Normal View History

2007-07-06 23:50:26 +00:00
#include "jnienv.h"
#include "builtin.h"
#include "machine.h"
using namespace vm;
namespace {
2007-07-07 18:09:16 +00:00
bool
find(Thread* t, Thread* o)
{
if (t == o) return true;
for (Thread* p = t->peer; p; p = p->peer) {
if (p == o) return true;
}
if (t->child) return find(t->child, o);
return false;
}
void
join(Thread* t, Thread* o)
{
if (t != o) {
o->systemThread->join();
}
}
void
dispose(Thread* t, Thread* o, bool remove)
{
if (remove) {
if (o->parent) {
if (o->child) {
o->parent->child = o->child;
if (o->peer) {
o->peer->peer = o->child->peer;
o->child->peer = o->peer;
}
} else if (o->peer) {
o->parent->child = o->peer;
} else {
o->parent->child = 0;
}
} else if (o->child) {
t->vm->rootThread = o->child;
if (o->peer) {
o->peer->peer = o->child->peer;
o->child->peer = o->peer;
}
} else if (o->peer) {
t->vm->rootThread = o->peer;
} else {
abort(t);
}
assert(t, not find(t->vm->rootThread, o));
}
o->dispose();
}
void
joinAll(Thread* m, Thread* o)
{
for (Thread* p = o->child; p;) {
Thread* child = p;
p = p->peer;
joinAll(m, child);
}
join(m, o);
}
void
disposeAll(Thread* m, Thread* o)
{
for (Thread* p = o->child; p;) {
Thread* child = p;
p = p->peer;
disposeAll(m, child);
}
dispose(m, o, false);
}
2007-07-06 23:50:26 +00:00
void
2007-07-07 18:09:16 +00:00
killZombies(Thread* t, Thread* o)
2007-07-06 23:50:26 +00:00
{
2007-07-07 18:09:16 +00:00
for (Thread* p = o->child; p;) {
Thread* child = p;
p = p->peer;
killZombies(t, child);
}
if (o->state == Thread::ZombieState) {
join(t, o);
dispose(t, o, true);
}
}
2007-07-07 23:47:35 +00:00
void
visitRoots(Thread* t, Heap::Visitor* v)
{
if (t->state != Thread::ZombieState) {
t->heapIndex = 0;
v->visit(&(t->javaThread));
v->visit(&(t->code));
v->visit(&(t->exception));
for (unsigned i = 0; i < t->sp; ++i) {
if (t->stack[i * 2] == ObjectTag) {
v->visit(reinterpret_cast<object*>(t->stack + (i * 2) + 1));
}
}
for (Thread::Protector* p = t->protector; p; p = p->next) {
v->visit(p->p);
}
}
for (Thread* c = t->child; c; c = c->peer) {
visitRoots(c, v);
}
}
void
postCollect(Thread* t)
{
if (t->large) {
t->vm->system->free(t->large);
t->large = 0;
}
for (Thread* c = t->child; c; c = c->peer) {
postCollect(c);
}
}
2007-07-07 18:09:16 +00:00
void
collect(Thread* t, Heap::CollectionType type)
{
Machine* m = t->vm;
2007-07-06 23:50:26 +00:00
class Client: public Heap::Client {
public:
Client(Machine* m): m(m) { }
virtual void visitRoots(Heap::Visitor* v) {
v->visit(&(m->classMap));
v->visit(&(m->bootstrapClassMap));
v->visit(&(m->builtinMap));
v->visit(&(m->monitorMap));
v->visit(&(m->types));
2007-07-07 18:09:16 +00:00
for (Thread* t = m->rootThread; t; t = t->peer) {
2007-07-06 23:50:26 +00:00
::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);
}
}
2007-07-07 23:47:35 +00:00
v->visit(&(m->finalizers));
v->visit(&(m->doomed));
2007-07-06 23:50:26 +00:00
for (object p = m->weakReferences; p;) {
object o = jreferenceTarget(t, p);
object followed = m->heap->follow(o);
if (followed == o) {
// object has not been collected
jreferenceTarget(t, p) = 0;
} else {
jreferenceTarget(t, p) = followed;
}
object last = p;
2007-07-07 23:47:35 +00:00
p = jreferenceNext(t, p);
jreferenceNext(t, last) = 0;
2007-07-06 23:50:26 +00:00
}
}
virtual unsigned sizeInWords(object o) {
Thread* t = m->rootThread;
o = m->heap->follow(mask(o));
return extendedSize
(t, o, baseSize(t, o, m->heap->follow(objectClass(t, o))));
}
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));
object class_ = m->heap->follow(objectClass(t, o));
unsigned base = baseSize(t, o, class_);
unsigned n = extendedSize(t, o, base);
memcpy(dst, o, n * BytesPerWord);
if (hashTaken(t, o)) {
cast<uintptr_t>(dst, 0) &= PointerMask;
cast<uintptr_t>(dst, 0) |= ExtendedMark;
2007-07-07 23:47:35 +00:00
extendedWord(t, dst, base) = takeHash(t, o);
2007-07-06 23:50:26 +00:00
}
if (classVmFlags(t, class_) & WeakReferenceFlag) {
2007-07-07 23:47:35 +00:00
fprintf(stderr, "weak reference to %p at %p\n",
jreferenceTarget(t, dst),
&jreferenceTarget(t, dst));
jreferenceNext(t, dst) = m->weakReferences;
2007-07-06 23:50:26 +00:00
m->weakReferences = dst;
}
}
virtual void walk(void* p, Heap::Walker* w) {
Thread* t = m->rootThread;
p = m->heap->follow(mask(p));
object class_ = m->heap->follow(objectClass(t, p));
object objectMask = m->heap->follow(classObjectMask(t, class_));
if (objectMask) {
// fprintf(stderr, "p: %p; class: %p; mask: %p; mask length: %d\n",
// p, class_, objectMask, intArrayLength(t, objectMask));
unsigned fixedSize = classFixedSize(t, class_);
unsigned arrayElementSize = classArrayElementSize(t, class_);
unsigned arrayLength
= (arrayElementSize ? cast<uint32_t>(p, fixedSize - 4) : 0);
int mask[intArrayLength(t, objectMask)];
memcpy(mask, &intArrayBody(t, objectMask, 0),
intArrayLength(t, objectMask) * 4);
// fprintf
// (stderr,
// "fixed size: %d; array length: %d; element size: %d; mask: %x\n",
// fixedSize, arrayLength, arrayElementSize, mask[0]);
unsigned fixedSizeInWords = divide(fixedSize, BytesPerWord);
unsigned arrayElementSizeInWords
= divide(arrayElementSize, BytesPerWord);
for (unsigned i = 0; i < fixedSizeInWords; ++i) {
2007-07-07 23:47:35 +00:00
if (mask[wordOf(i)] & (static_cast<uintptr_t>(1) << bitOf(i))) {
2007-07-06 23:50:26 +00:00
if (not w->visit(i)) {
return;
}
}
}
bool arrayObjectElements = false;
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
unsigned k = fixedSizeInWords + j;
if (mask[wordOf(k)] & (static_cast<uintptr_t>(1) << bitOf(k))) {
arrayObjectElements = true;
break;
}
}
if (arrayObjectElements) {
for (unsigned i = 0; i < arrayLength; ++i) {
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
unsigned k = fixedSizeInWords + j;
if (mask[wordOf(k)] & (static_cast<uintptr_t>(1) << bitOf(k))) {
if (not w->visit
(fixedSizeInWords + (i * arrayElementSizeInWords) + j))
{
return;
}
}
}
}
}
} else {
w->visit(0);
}
}
private:
Machine* m;
} it(m);
m->unsafe = true;
m->heap->collect(type, &it);
m->unsafe = false;
postCollect(m->rootThread);
2007-07-07 23:47:35 +00:00
for (object f = m->doomed; f; f = finalizerNext(t, f)) {
2007-07-06 23:50:26 +00:00
reinterpret_cast<void (*)(Thread*, object)>(finalizerFinalize(t, f))
(t, finalizerTarget(t, f));
}
m->doomed = 0;
m->weakReferences = 0;
2007-07-07 18:09:16 +00:00
killZombies(t, m->rootThread);
2007-07-06 23:50:26 +00:00
}
void
removeMonitor(Thread* t, object o)
{
abort(t);
2007-07-06 23:50:26 +00:00
hashMapRemove(t, t->vm->monitorMap, o, objectHash, referenceEqual);
}
object
makeByteArray(Thread* t, const char* format, va_list a)
{
static const unsigned Size = 256;
char buffer[Size];
vsnprintf(buffer, Size - 1, format, a);
object s = makeByteArray(t, strlen(buffer) + 1, false);
memcpy(&byteArrayBody(t, s, 0), buffer, byteArrayLength(t, s));
return s;
}
} // namespace
namespace vm {
Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder):
system(system),
heap(heap),
classFinder(classFinder),
rootThread(0),
exclusive(0),
activeCount(0),
liveCount(0),
stateLock(0),
heapLock(0),
classLock(0),
finalizerLock(0),
libraries(0),
classMap(0),
bootstrapClassMap(0),
builtinMap(0),
monitorMap(0),
types(0),
finalizers(0),
doomed(0),
weakReferences(0),
unsafe(false)
{
jni::populate(&jniEnvVTable);
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(&finalizerLock)))
{
system->abort();
}
}
void
Machine::dispose()
{
stateLock->dispose();
heapLock->dispose();
classLock->dispose();
finalizerLock->dispose();
if (libraries) {
libraries->dispose();
}
if (rootThread) {
rootThread->dispose();
}
}
2007-07-07 18:09:16 +00:00
Thread::Thread(Machine* m, Allocator* allocator, object javaThread,
Thread* parent):
2007-07-06 23:50:26 +00:00
vtable(&(m->jniEnvVTable)),
vm(m),
2007-07-07 18:09:16 +00:00
allocator(allocator),
parent(parent),
peer((parent ? parent->child : 0)),
2007-07-06 23:50:26 +00:00
child(0),
state(NoState),
2007-07-07 18:09:16 +00:00
systemThread(0),
javaThread(javaThread),
2007-07-06 23:50:26 +00:00
code(0),
exception(0),
2007-07-07 18:09:16 +00:00
large(0),
2007-07-06 23:50:26 +00:00
ip(0),
sp(0),
frame(-1),
heapIndex(0),
2007-07-07 18:09:16 +00:00
protector(0)
2007-07-06 23:50:26 +00:00
{
2007-07-07 18:09:16 +00:00
if (parent == 0) {
assert(this, m->rootThread == 0);
assert(this, javaThread == 0);
2007-07-06 23:50:26 +00:00
m->rootThread = this;
m->unsafe = true;
2007-07-07 18:09:16 +00:00
if (not m->system->success(m->system->attach(&systemThread))) {
abort(this);
}
2007-07-06 23:50:26 +00:00
Thread* t = this;
#include "type-initializations.cpp"
object arrayClass = arrayBody(t, t->vm->types, Machine::ArrayType);
set(t, cast<object>(t->vm->types, 0), arrayClass);
object classClass = arrayBody(t, m->types, Machine::ClassType);
set(t, cast<object>(classClass, 0), classClass);
object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType);
set(t, cast<object>(intArrayClass, 0), classClass);
2007-07-07 23:47:35 +00:00
set(t, classSuper(t, intArrayClass),
arrayBody(t, m->types, Machine::JobjectType));
2007-07-06 23:50:26 +00:00
m->unsafe = false;
m->bootstrapClassMap = makeHashMap(this, 0, 0);
#include "type-java-initializations.cpp"
classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType))
|= WeakReferenceFlag;
m->classMap = makeHashMap(this, 0, 0);
m->builtinMap = makeHashMap(this, 0, 0);
m->monitorMap = makeHashMap(this, 0, 0);
builtin::populate(t, m->builtinMap);
2007-07-07 18:09:16 +00:00
javaThread = makeThread(t, 0, reinterpret_cast<int64_t>(t));
} else {
threadPeer(this, javaThread) = reinterpret_cast<jlong>(this);
parent->child = this;
}
}
void
Thread::exit()
{
if (state != Thread::ExitState and
state != Thread::ZombieState)
{
enter(this, Thread::ExclusiveState);
if (vm->liveCount == 1) {
vm::exit(this);
} else {
enter(this, Thread::ZombieState);
}
2007-07-06 23:50:26 +00:00
}
}
void
Thread::dispose()
{
2007-07-07 18:09:16 +00:00
if (large) {
vm->system->free(large);
large = 0;
}
if (systemThread) {
systemThread->dispose();
systemThread = 0;
}
if (allocator) {
allocator->free(this);
allocator = 0;
2007-07-06 23:50:26 +00:00
}
}
2007-07-07 18:09:16 +00:00
void
exit(Thread* t)
{
enter(t, Thread::ExitState);
joinAll(t, t->vm->rootThread);
for (object f = t->vm->finalizers; f; f = finalizerNext(t, f)) {
reinterpret_cast<void (*)(Thread*, object)>(finalizerFinalize(t, f))
(t, finalizerTarget(t, f));
}
disposeAll(t, t->vm->rootThread);
}
2007-07-06 23:50:26 +00:00
void
enter(Thread* t, Thread::State s)
{
if (s == t->state) return;
ACQUIRE_RAW(t, t->vm->stateLock);
switch (s) {
case Thread::ExclusiveState: {
assert(t, t->state == Thread::ActiveState);
while (t->vm->exclusive) {
// another thread got here first.
2007-07-07 18:09:16 +00:00
ENTER(t, Thread::IdleState);
2007-07-06 23:50:26 +00:00
}
t->state = Thread::ExclusiveState;
t->vm->exclusive = t;
while (t->vm->activeCount > 1) {
t->vm->stateLock->wait(t, 0);
}
} break;
case Thread::IdleState:
case Thread::ZombieState: {
switch (t->state) {
case Thread::ExclusiveState: {
assert(t, t->vm->exclusive == t);
t->vm->exclusive = 0;
} break;
case Thread::ActiveState: break;
default: abort(t);
}
-- t->vm->activeCount;
if (s == Thread::ZombieState) {
-- t->vm->liveCount;
}
t->state = s;
t->vm->stateLock->notifyAll(t);
} break;
case Thread::ActiveState: {
switch (t->state) {
case Thread::ExclusiveState: {
assert(t, t->vm->exclusive == t);
t->state = s;
t->vm->exclusive = 0;
t->vm->stateLock->notifyAll(t);
} break;
case Thread::NoState:
case Thread::IdleState: {
while (t->vm->exclusive) {
t->vm->stateLock->wait(t, 0);
}
++ t->vm->activeCount;
if (t->state == Thread::NoState) {
++ t->vm->liveCount;
}
t->state = s;
} break;
default: abort(t);
}
} break;
case Thread::ExitState: {
switch (t->state) {
case Thread::ExclusiveState: {
assert(t, t->vm->exclusive == t);
t->vm->exclusive = 0;
} break;
case Thread::ActiveState: break;
default: abort(t);
}
-- t->vm->activeCount;
t->state = s;
while (t->vm->liveCount > 1) {
t->vm->stateLock->wait(t, 0);
}
} break;
default: abort(t);
}
}
object
allocate2(Thread* t, unsigned sizeInBytes)
{
2007-07-07 18:09:16 +00:00
if (sizeInBytes > Thread::HeapSizeInBytes and t->large == 0) {
2007-07-06 23:50:26 +00:00
return allocateLarge(t, sizeInBytes);
}
ACQUIRE_RAW(t, t->vm->stateLock);
2007-07-07 18:09:16 +00:00
while (t->vm->exclusive and t->vm->exclusive != t) {
2007-07-06 23:50:26 +00:00
// another thread wants to enter the exclusive state, either for a
// collection or some other reason. We give it a chance here.
2007-07-07 18:09:16 +00:00
ENTER(t, Thread::IdleState);
2007-07-06 23:50:26 +00:00
}
if (t->heapIndex + divide(sizeInBytes, BytesPerWord)
>= Thread::HeapSizeInWords)
{
2007-07-07 18:09:16 +00:00
ENTER(t, Thread::ExclusiveState);
collect(t, Heap::MinorCollection);
2007-07-06 23:50:26 +00:00
}
if (sizeInBytes > Thread::HeapSizeInBytes) {
return allocateLarge(t, sizeInBytes);
} else {
return allocateSmall(t, sizeInBytes);
}
}
object
makeByteArray(Thread* t, const char* format, ...)
{
va_list a;
va_start(a, format);
object s = ::makeByteArray(t, format, a);
va_end(a);
return s;
}
object
makeString(Thread* t, const char* format, ...)
{
va_list a;
va_start(a, format);
object s = ::makeByteArray(t, format, a);
va_end(a);
return makeString(t, s, 0, byteArrayLength(t, s), 0);
}
void
stringChars(Thread* t, object string, char* chars)
{
object data = stringData(t, string);
if (objectClass(t, data)
== arrayBody(t, t->vm->types, Machine::ByteArrayType))
{
memcpy(chars,
&byteArrayBody(t, data, stringOffset(t, string)),
stringLength(t, string));
} else {
for (int i = 0; i < stringLength(t, string); ++i) {
chars[i] = charArrayBody(t, data, stringOffset(t, string) + i);
}
}
chars[stringLength(t, string)] = 0;
}
2007-07-06 23:50:26 +00:00
object
hashMapFindNode(Thread* t, object map, object key,
uint32_t (*hash)(Thread*, object),
bool (*equal)(Thread*, object, object))
{
object array = hashMapArray(t, map);
if (array) {
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
object n = arrayBody(t, array, index);
while (n) {
if (equal(t, key, tripleFirst(t, n))) {
return n;
}
n = tripleThird(t, n);
}
}
return 0;
}
void
hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object),
unsigned size)
{
PROTECT(t, map);
object oldArray = hashMapArray(t, map);
unsigned oldLength = (oldArray ? arrayLength(t, oldArray) : 0);
PROTECT(t, oldArray);
unsigned newLength = nextPowerOfTwo(size);
object newArray = makeArray(t, newLength, true);
if (oldArray) {
for (unsigned i = 0; i < oldLength; ++i) {
object next;
for (object p = arrayBody(t, oldArray, i); p; p = next) {
next = tripleThird(t, p);
object key = tripleFirst(t, p);
unsigned index = hash(t, key) & (newLength - 1);
object n = arrayBody(t, newArray, index);
set(t, tripleThird(t, p), n);
set(t, arrayBody(t, newArray, index), p);
}
}
}
set(t, hashMapArray(t, map), newArray);
}
void
hashMapInsert(Thread* t, object map, object key, object value,
uint32_t (*hash)(Thread*, object))
{
object array = hashMapArray(t, map);
PROTECT(t, array);
++ hashMapSize(t, map);
if (array == 0 or hashMapSize(t, map) >= arrayLength(t, array) * 2) {
PROTECT(t, map);
PROTECT(t, key);
PROTECT(t, value);
hashMapResize(t, map, hash, array ? arrayLength(t, array) * 2 : 16);
array = hashMapArray(t, map);
}
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
object n = arrayBody(t, array, index);
n = makeTriple(t, key, value, n);
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, key, tripleFirst(t, n))) {
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
makeTrace(Thread* t, int frame)
{
unsigned count = 0;
for (int f = frame; f >= 0; f = frameNext(t, f)) {
++ count;
}
object trace = makeObjectArray
(t, arrayBody(t, t->vm->types, Machine::StackTraceElementType),
count, true);
PROTECT(t, trace);
unsigned index = 0;
for (int f = frame; f >= 0; f = frameNext(t, f)) {
object e = makeStackTraceElement(t, frameMethod(t, f), frameIp(t, f));
set(t, objectArrayBody(t, trace, index++), e);
}
return trace;
}
object
hashMapIterator(Thread* t, object map)
{
object array = hashMapArray(t, map);
if (array) {
for (unsigned i = 0; i < arrayLength(t, array); ++i) {
if (arrayBody(t, array, i)) {
return makeHashMapIterator(t, map, arrayBody(t, array, i), i + 1);
}
}
}
return 0;
}
object
hashMapIteratorNext(Thread* t, object it)
{
object map = hashMapIteratorMap(t, it);
object node = hashMapIteratorNode(t, it);
unsigned index = hashMapIteratorIndex(t, it);
if (tripleThird(t, node)) {
return makeHashMapIterator(t, map, tripleThird(t, node), index + 1);
} else {
object array = hashMapArray(t, map);
for (unsigned i = index; i < arrayLength(t, array); ++i) {
if (arrayBody(t, array, i)) {
return makeHashMapIterator(t, map, arrayBody(t, array, i), i + 1);
}
}
return 0;
}
}
void
listAppend(Thread* t, object list, object value)
{
PROTECT(t, list);
++ listSize(t, list);
object p = makePair(t, value, 0);
if (listFront(t, list)) {
set(t, pairSecond(t, listRear(t, list)), p);
} else {
set(t, listFront(t, list), p);
}
set(t, listRear(t, list), p);
}
void
addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object))
{
PROTECT(t, target);
ACQUIRE(t, t->vm->finalizerLock);
2007-07-07 18:09:16 +00:00
t->vm->finalizers = makeFinalizer
(t, target, reinterpret_cast<void*>(finalize), t->vm->finalizers);
2007-07-06 23:50:26 +00:00
}
System::Monitor*
objectMonitor(Thread* t, object o)
{
object p = hashMapFind(t, t->vm->monitorMap, o, objectHash, referenceEqual);
if (p) {
return static_cast<System::Monitor*>(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));
p = makePointer(t, m);
PROTECT(t, p);
object wr = makeWeakReference(t, o, 0);
hashMapInsert(t, t->vm->monitorMap, wr, p, referenceHash);
addFinalizer(t, o, removeMonitor);
return m;
}
}
#include "type-constructors.cpp"
} // namespace vm