mirror of
https://github.com/corda/corda.git
synced 2024-12-29 09:18:58 +00:00
sketch Machine and Thread classes; refine allocation and thread state transitions
This commit is contained in:
parent
f6e369c424
commit
4ecf7917cc
250
src/vm.cpp
250
src/vm.cpp
@ -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:
|
||||||
|
Loading…
Reference in New Issue
Block a user