sketch Machine and Thread classes; refine allocation and thread state transitions

This commit is contained in:
Joel Dice 2007-06-02 20:00:23 -06:00
parent f6e369c424
commit 4ecf7917cc

View File

@ -1,8 +1,94 @@
#include "common.h"
#include "system.h"
#include "heap.h"
namespace { namespace {
typedef void* object;
class Thread;
class Machine {
public:
System* sys;
Heap* heap;
Thread* rootThread;
Thread* exclusive;
unsigned activeCount;
unsigned liveCount;
System::Monitor* stateLock;
};
class Thread {
public:
enum State {
NoState,
ActiveState,
IdleState,
ZombieState,
ExclusiveState,
ExitState
};
static const unsigned HeapSize = 64 * 1024;
static const unsigned StackSize = 64 * 1024;
Machine* vm;
Thread* next;
Thread* child;
State state;
object frame;
object code;
object exception;
unsigned sp;
unsigned heapIndex;
object stack[StackSize];
object heap[HeapSize];
};
inline void NO_RETURN
abort(Thread* t)
{
t->vm->sys->abort();
}
inline void
assert(Thread* t, bool v)
{
if (UNLIKELY(not v)) abort(t);
}
void
init(Machine* m, System* sys, Heap* heap)
{
sys->zero(m, sizeof(Machine));
m->sys = sys;
m->heap = heap;
if (not sys->success(sys->make(&(m->stateLock)))) {
sys->abort();
}
}
void
dispose(Machine* m)
{
m->stateLock->dispose();
}
void
init(Thread* t, Machine* m)
{
m->sys->zero(m, sizeof(Thread));
t->vm = m;
m->rootThread = t;
t->state = Thread::NoState;
}
void void
iterate(Thread* t, Heap::Visitor* v) iterate(Thread* t, Heap::Visitor* v)
{ {
t->heapIndex = 0;
v->visit(&(t->frame)); v->visit(&(t->frame));
v->visit(&(t->code)); v->visit(&(t->code));
v->visit(&(t->exception)); v->visit(&(t->exception));
@ -33,64 +119,144 @@ collect(Machine* m, Heap::CollectionType type)
Machine* machine; Machine* machine;
} it(m); } it(m);
m->heap.collect(type, &it); m->heap->collect(type, &it);
} }
object void
collectAndAllocate(Thread* t, unsigned size) enter(Thread* t, Thread::State s)
{ {
if (size > Thread::HeapSize) { if (s == state) return;
abort(); // not yet implemented
}
LOCK(t->vm->stateLock); ACQUIRE(t->vm->stateLock);
if (t->vm->exclusive) { switch (s) {
// enter idle state and wait for collection to finish. case ExclusiveState: {
t->state = Thread::IdleState; assert(t, state == ActiveState);
-- t->vm->activeCount;
t->vm->stateLock->notifyAll();
while (t->vm->exclusive) { while (t->vm->exclusive) {
t->vm->stateLock->wait(); // another thread got here first.
enter(t, Thread::IdleState);
enter(t, Thread::ActiveState);
} }
// wake up. t->state = ExclusiveState;
state = Thread::ActiveState;
++ t->vm->activeCount;
} else {
// enter exclusive state and wait for other threads to go idle.
t->vm->exclusive = t; t->vm->exclusive = t;
while (t->vm->activeCount > 1) { while (t->vm->activeCount > 1) {
t->vm->stateLock->wait(); t->vm->stateLock->wait();
} }
} break;
// collect. case IdleState:
collect(t->vm, Heap::MinorCollection); case ZombieState: {
switch (state) {
case ExclusiveState: {
assert(t, t->vm->exclusive == t);
t->vm->exclusive = 0;
} break;
case ActiveState: break;
default: abort(t);
}
-- t->vm->activeCount;
if (s == ZombieState) {
-- t->vm->liveCount;
}
t->state = s;
// signal collection finish.
t->vm->exclusive = 0;
t->vm->stateLock->notifyAll(); t->vm->stateLock->notifyAll();
} break;
case ActiveState: {
switch (state) {
case ExclusiveState: {
assert(t, t->vm->exclusive == t);
t->state = s;
t->vm->exclusive = 0;
t->vm->stateLock->notifyAll();
} break;
case NoState:
case IdleState: {
while (t->vm->exclusive) {
t->vm->stateLock->wait();
}
++ t->vm->activeCount;
if (state == NoState) {
++ t->vm->liveCount;
}
t->state = s;
} break;
default: abort(t);
}
} break;
case ExitState: {
switch (state) {
case ExclusiveState: {
assert(t, t->vm->exclusive == t);
t->vm->exclusive = 0;
} break;
case ActiveState: break;
default: abort(t);
}
-- t->vm->activeCount;
t->state = s;
while (t->vm->liveCount > 1) {
t->vm->stateLock->wait();
}
} break;
default: abort(t);
}
}
void
maybeYieldAndMaybeCollect(Thread* t, unsigned size)
{
if (size > Thread::HeapSize) {
// large object support not yet implemented.
abort(t);
} }
t->heapIndex += size; ACQUIRE(t->vm->stateLock);
return t->heap;
while (t->vm->exclusive) {
// another thread wants to enter the exclusive state, either for a
// collection or some other reason. We give it a chance here.
enter(t, Thread::IdleState);
enter(t, Thread::ActiveState);
}
if (t->heapIndex + size >= Thread::HeapSize) {
enter(t, Thread::ExclusiveState);
collect(t->vm, Heap::MinorCollection);
enter(t, Thread::ActiveState);
}
} }
inline object inline object
allocate(Thread* t, unsigned size) allocate(Thread* t, unsigned size)
{ {
if (UNLIKELY(size > Thread::HeapSize - t->heapIndex if (UNLIKELY(t->heapIndex + size >= Thread::HeapSize
or t->vm->exclusive)) or t->vm->exclusive))
{ {
return collectAndAllocate(t, size); maybeYieldAndMaybeCollect(t, size);
} else {
object o = t->heap + t->heapIndex;
t->heapIndex += size;
return o;
} }
object o = t->heap + t->heapIndex;
t->heapIndex += size;
return o;
} }
object object
@ -192,7 +358,7 @@ run(Thread* t)
if (t->exception) goto throw_; if (t->exception) goto throw_;
object array = makeObjectArray(t, class_, c); object array = makeObjectArray(t, class_, c);
memset(objectArrayBody(array), 0, c * 4); t->vm->sys->zero(objectArrayBody(array), c * 4);
PUSH(array); PUSH(array);
} else { } else {
@ -225,7 +391,7 @@ run(Thread* t)
t->exception = makeNullPointerException(t, 0); t->exception = makeNullPointerException(t, 0);
goto throw_; goto throw_;
} }
} UNREACHABLE; } abort(t);
case astore: case astore:
case istore: case istore:
@ -268,7 +434,7 @@ run(Thread* t)
t->exception = makeNullPointerException(t, 0); t->exception = makeNullPointerException(t, 0);
} }
goto throw_; goto throw_;
} UNREACHABLE; } abort(t);
case baload: { case baload: {
object index; POP(index); object index; POP(index);
@ -1182,9 +1348,8 @@ run(Thread* t)
unsigned size = instanceSize(class_); unsigned size = instanceSize(class_);
object instance = allocate(t, size); object instance = allocate(t, size);
*static_cast<object*>(instance) = class_; *static_cast<object*>(instance) = class_;
memset(static_cast<object*>(instance) + sizeof(object), t->vm->sys->zero(static_cast<object*>(instance) + sizeof(object),
0, size - sizeof(object));
size - sizeof(object));
PUSH(instance); PUSH(instance);
} goto loop; } goto loop;
@ -1240,12 +1405,11 @@ run(Thread* t)
factor = 8; factor = 8;
break; break;
default: UNREACHABLE; default: abort(t);
} }
memset(static_cast<object*>(instance) + (sizeof(object) * 2), t->vm->sys->zero(static_cast<object*>(instance) + (sizeof(object) * 2),
0, c * factor);
c * factor);
PUSH(array); PUSH(array);
} else { } else {
@ -1379,7 +1543,7 @@ run(Thread* t)
case wide: goto wide; case wide: goto wide;
default: UNREACHABLE; default: abort(t);
} }
wide: wide:
@ -1423,7 +1587,7 @@ run(Thread* t)
ip = intValue(frameBody(t->frame)[(index1 << 8) | index2]); ip = intValue(frameBody(t->frame)[(index1 << 8) | index2]);
} goto loop; } goto loop;
default: UNREACHABLE; default: abort(t);
} }
invoke: invoke: