mirror of
https://github.com/corda/corda.git
synced 2025-04-03 17:39:09 +00:00
progress on thread support
This commit is contained in:
parent
3bd267b47a
commit
e5bea7a455
@ -2,11 +2,11 @@ public class TestThreads implements Runnable {
|
||||
|
||||
public static void main(String[] args) {
|
||||
TestThreads test = new TestThreads();
|
||||
Thread th = new Thread(test);
|
||||
Thread thread = new Thread(test);
|
||||
|
||||
try {
|
||||
synchronized (test) {
|
||||
th.start();
|
||||
thread.start();
|
||||
test.wait();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
|
@ -2,12 +2,13 @@ package java.lang;
|
||||
|
||||
public class Thread implements Runnable {
|
||||
private final Runnable task;
|
||||
private long peer;
|
||||
|
||||
public Thread(Runnable task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
public native void start();
|
||||
public synchronized native void start();
|
||||
|
||||
public void run() {
|
||||
if (task != null) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "builtin.h"
|
||||
#include "machine.h"
|
||||
#include "run.h"
|
||||
|
||||
namespace vm {
|
||||
namespace builtin {
|
||||
@ -63,6 +64,43 @@ trace(Thread* t, jint skipCount)
|
||||
return pushReference(t, makeTrace(t, frame));
|
||||
}
|
||||
|
||||
void
|
||||
start(Thread* t, jobject this_)
|
||||
{
|
||||
Thread* p = reinterpret_cast<Thread*>(threadPeer(t, *this_));
|
||||
if (p) {
|
||||
object message = makeString(t, "thread already started");
|
||||
t->exception = makeIllegalStateException(t, message);
|
||||
} else {
|
||||
p = new (t->vm->system->allocate(sizeof(Thread)))
|
||||
Thread(t->vm, t->vm->system, *this_, t);
|
||||
|
||||
enter(p, Thread::ActiveState);
|
||||
|
||||
class Runnable: public System::Runnable {
|
||||
public:
|
||||
Runnable(Thread* t): t(t) { }
|
||||
|
||||
virtual void run(System::Thread* st) {
|
||||
t->systemThread = st;
|
||||
|
||||
vm::run(t, "java/lang/Thread", "run", "()V", t->javaThread);
|
||||
|
||||
t->exit();
|
||||
}
|
||||
|
||||
Thread* t;
|
||||
} r(p);
|
||||
|
||||
if (not t->vm->system->success(t->vm->system->start(&r))) {
|
||||
p->exit();
|
||||
|
||||
object message = makeString(t, "unable to start native thread");
|
||||
t->exception = makeRuntimeException(t, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
populate(Thread* t, object map)
|
||||
{
|
||||
@ -76,6 +114,8 @@ populate(Thread* t, object map)
|
||||
reinterpret_cast<void*>(loadLibrary) },
|
||||
{ "Java_java_lang_Throwable_trace",
|
||||
reinterpret_cast<void*>(trace) },
|
||||
{ "Java_java_lang_Thread_start",
|
||||
reinterpret_cast<void*>(start) },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
235
src/machine.cpp
235
src/machine.cpp
@ -9,23 +9,25 @@ namespace {
|
||||
void
|
||||
visitRoots(Thread* t, Heap::Visitor* v)
|
||||
{
|
||||
t->heapIndex = 0;
|
||||
if (t->state != Thread::ZombieState) {
|
||||
t->heapIndex = 0;
|
||||
|
||||
v->visit(&(t->thread));
|
||||
v->visit(&(t->code));
|
||||
v->visit(&(t->exception));
|
||||
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 (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::Protector* p = t->protector; p; p = p->next) {
|
||||
v->visit(p->p);
|
||||
}
|
||||
|
||||
for (Thread* c = t->child; c; c = c->next) {
|
||||
for (Thread* c = t->child; c; c = c->peer) {
|
||||
visitRoots(c, v);
|
||||
}
|
||||
}
|
||||
@ -33,17 +35,116 @@ visitRoots(Thread* t, Heap::Visitor* v)
|
||||
void
|
||||
postCollect(Thread* t)
|
||||
{
|
||||
Chain::dispose(t->vm->system, t->chain);
|
||||
t->chain = 0;
|
||||
if (t->large) {
|
||||
t->vm->system->free(t->large);
|
||||
t->large = 0;
|
||||
}
|
||||
|
||||
for (Thread* c = t->child; c; c = c->next) {
|
||||
for (Thread* c = t->child; c; c = c->peer) {
|
||||
postCollect(c);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
collect(Machine* m, Heap::CollectionType type)
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
killZombies(Thread* t, Thread* o)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
collect(Thread* t, Heap::CollectionType type)
|
||||
{
|
||||
Machine* m = t->vm;
|
||||
|
||||
class Client: public Heap::Client {
|
||||
public:
|
||||
Client(Machine* m): m(m) { }
|
||||
@ -55,7 +156,7 @@ collect(Machine* m, Heap::CollectionType type)
|
||||
v->visit(&(m->monitorMap));
|
||||
v->visit(&(m->types));
|
||||
|
||||
for (Thread* t = m->rootThread; t; t = t->next) {
|
||||
for (Thread* t = m->rootThread; t; t = t->peer) {
|
||||
::visitRoots(t, v);
|
||||
}
|
||||
|
||||
@ -221,7 +322,6 @@ collect(Machine* m, Heap::CollectionType type)
|
||||
|
||||
postCollect(m->rootThread);
|
||||
|
||||
Thread* t = m->rootThread;
|
||||
for (object f = m->doomed; f; f = tripleThird(t, f)) {
|
||||
reinterpret_cast<void (*)(Thread*, object)>(finalizerFinalize(t, f))
|
||||
(t, finalizerTarget(t, f));
|
||||
@ -229,6 +329,8 @@ collect(Machine* m, Heap::CollectionType type)
|
||||
m->doomed = 0;
|
||||
|
||||
m->weakReferences = 0;
|
||||
|
||||
killZombies(t, m->rootThread);
|
||||
}
|
||||
|
||||
void
|
||||
@ -306,26 +408,37 @@ Machine::dispose()
|
||||
}
|
||||
}
|
||||
|
||||
Thread::Thread(Machine* m):
|
||||
Thread::Thread(Machine* m, Allocator* allocator, object javaThread,
|
||||
Thread* parent):
|
||||
vtable(&(m->jniEnvVTable)),
|
||||
vm(m),
|
||||
next(0),
|
||||
allocator(allocator),
|
||||
parent(parent),
|
||||
peer((parent ? parent->child : 0)),
|
||||
child(0),
|
||||
state(NoState),
|
||||
thread(0),
|
||||
systemThread(0),
|
||||
javaThread(javaThread),
|
||||
code(0),
|
||||
exception(0),
|
||||
large(0),
|
||||
ip(0),
|
||||
sp(0),
|
||||
frame(-1),
|
||||
heapIndex(0),
|
||||
protector(0),
|
||||
chain(0)
|
||||
protector(0)
|
||||
{
|
||||
if (m->rootThread == 0) {
|
||||
if (parent == 0) {
|
||||
assert(this, m->rootThread == 0);
|
||||
assert(this, javaThread == 0);
|
||||
|
||||
m->rootThread = this;
|
||||
m->unsafe = true;
|
||||
|
||||
if (not m->system->success(m->system->attach(&systemThread))) {
|
||||
abort(this);
|
||||
}
|
||||
|
||||
Thread* t = this;
|
||||
|
||||
#include "type-initializations.cpp"
|
||||
@ -353,17 +466,62 @@ Thread::Thread(Machine* m):
|
||||
m->monitorMap = makeHashMap(this, 0, 0);
|
||||
|
||||
builtin::populate(t, m->builtinMap);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Thread::dispose()
|
||||
{
|
||||
Chain::dispose(vm->system, chain);
|
||||
|
||||
for (Thread* c = child; c; c = c->next) {
|
||||
c->dispose();
|
||||
if (large) {
|
||||
vm->system->free(large);
|
||||
large = 0;
|
||||
}
|
||||
|
||||
if (systemThread) {
|
||||
systemThread->dispose();
|
||||
systemThread = 0;
|
||||
}
|
||||
|
||||
if (allocator) {
|
||||
allocator->free(this);
|
||||
allocator = 0;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
@ -379,8 +537,7 @@ enter(Thread* t, Thread::State s)
|
||||
|
||||
while (t->vm->exclusive) {
|
||||
// another thread got here first.
|
||||
enter(t, Thread::IdleState);
|
||||
enter(t, Thread::ActiveState);
|
||||
ENTER(t, Thread::IdleState);
|
||||
}
|
||||
|
||||
t->state = Thread::ExclusiveState;
|
||||
@ -468,25 +625,23 @@ enter(Thread* t, Thread::State s)
|
||||
object
|
||||
allocate2(Thread* t, unsigned sizeInBytes)
|
||||
{
|
||||
if (sizeInBytes > Thread::HeapSizeInBytes and t->chain == 0) {
|
||||
if (sizeInBytes > Thread::HeapSizeInBytes and t->large == 0) {
|
||||
return allocateLarge(t, sizeInBytes);
|
||||
}
|
||||
|
||||
ACQUIRE_RAW(t, t->vm->stateLock);
|
||||
|
||||
while (t->vm->exclusive) {
|
||||
while (t->vm->exclusive and t->vm->exclusive != t) {
|
||||
// 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);
|
||||
ENTER(t, Thread::IdleState);
|
||||
}
|
||||
|
||||
if (t->heapIndex + divide(sizeInBytes, BytesPerWord)
|
||||
>= Thread::HeapSizeInWords)
|
||||
{
|
||||
enter(t, Thread::ExclusiveState);
|
||||
collect(t->vm, Heap::MinorCollection);
|
||||
enter(t, Thread::ActiveState);
|
||||
ENTER(t, Thread::ExclusiveState);
|
||||
collect(t, Heap::MinorCollection);
|
||||
}
|
||||
|
||||
if (sizeInBytes > Thread::HeapSizeInBytes) {
|
||||
@ -708,8 +863,8 @@ addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object))
|
||||
|
||||
ACQUIRE(t, t->vm->finalizerLock);
|
||||
|
||||
object p = makePointer(t, reinterpret_cast<void*>(finalize));
|
||||
t->vm->finalizers = makeTriple(t, target, p, t->vm->finalizers);
|
||||
t->vm->finalizers = makeFinalizer
|
||||
(t, target, reinterpret_cast<void*>(finalize), t->vm->finalizers);
|
||||
}
|
||||
|
||||
System::Monitor*
|
||||
|
@ -23,7 +23,7 @@ namespace vm {
|
||||
|
||||
const bool Verbose = false;
|
||||
const bool Debug = false;
|
||||
const bool DebugRun = false;
|
||||
const bool DebugRun = true;
|
||||
const bool DebugStack = false;
|
||||
|
||||
const uintptr_t HashTakenMark = 1;
|
||||
@ -1114,28 +1114,6 @@ class Machine {
|
||||
JNIEnvVTable jniEnvVTable;
|
||||
};
|
||||
|
||||
class Chain {
|
||||
public:
|
||||
Chain(Chain* next): next(next) { }
|
||||
|
||||
static unsigned footprint(unsigned sizeInBytes) {
|
||||
return sizeof(Chain) + sizeInBytes;
|
||||
}
|
||||
|
||||
uint8_t* data() {
|
||||
return reinterpret_cast<uint8_t*>(this) + sizeof(Chain);
|
||||
}
|
||||
|
||||
static void dispose(System* s, Chain* c) {
|
||||
if (c) {
|
||||
if (c->next) dispose(s, c->next);
|
||||
s->free(c);
|
||||
}
|
||||
}
|
||||
|
||||
Chain* next;
|
||||
};
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
enum State {
|
||||
@ -1168,24 +1146,32 @@ class Thread {
|
||||
static const unsigned HeapSizeInWords = HeapSizeInBytes / BytesPerWord;
|
||||
static const unsigned StackSizeInWords = StackSizeInBytes / BytesPerWord;
|
||||
|
||||
Thread(Machine* m);
|
||||
Thread(Machine* m, Allocator* allocator, object javaThread, Thread* parent);
|
||||
|
||||
~Thread() {
|
||||
exit();
|
||||
}
|
||||
|
||||
void exit();
|
||||
void dispose();
|
||||
|
||||
JNIEnvVTable* vtable;
|
||||
Machine* vm;
|
||||
Thread* next;
|
||||
Allocator* allocator;
|
||||
Thread* parent;
|
||||
Thread* peer;
|
||||
Thread* child;
|
||||
State state;
|
||||
object thread;
|
||||
System::Thread* systemThread;
|
||||
object javaThread;
|
||||
object code;
|
||||
object exception;
|
||||
object large;
|
||||
unsigned ip;
|
||||
unsigned sp;
|
||||
int frame;
|
||||
unsigned heapIndex;
|
||||
Protector* protector;
|
||||
Chain* chain;
|
||||
uintptr_t stack[StackSizeInWords];
|
||||
object heap[HeapSizeInWords];
|
||||
};
|
||||
@ -1261,9 +1247,7 @@ expect(Thread* t, bool v)
|
||||
inline object
|
||||
allocateLarge(Thread* t, unsigned sizeInBytes)
|
||||
{
|
||||
void* p = t->vm->system->allocate(Chain::footprint(sizeInBytes));
|
||||
t->chain = new (p) Chain(t->chain);
|
||||
return t->chain->data();
|
||||
return t->large = t->vm->system->allocate(sizeInBytes);
|
||||
}
|
||||
|
||||
inline object
|
||||
@ -1319,6 +1303,14 @@ makeRuntimeException(Thread* t, object message)
|
||||
return makeRuntimeException(t, message, trace, 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeIllegalStateException(Thread* t, object message)
|
||||
{
|
||||
PROTECT(t, message);
|
||||
object trace = makeTrace(t);
|
||||
return makeIllegalStateException(t, message, trace, 0);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeArrayIndexOutOfBoundsException(Thread* t, object message)
|
||||
{
|
||||
@ -1781,6 +1773,20 @@ hashMapInsertOrReplace(Thread* t, object map, object key, object value,
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
hashMapInsertMaybe(Thread* t, object map, object key, object value,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
bool (*equal)(Thread*, object, object))
|
||||
{
|
||||
object n = hashMapFindNode(t, map, key, hash, equal);
|
||||
if (n == 0) {
|
||||
hashMapInsert(t, map, key, value, hash);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
hashMapRemove(Thread* t, object map, object key,
|
||||
uint32_t (*hash)(Thread*, object),
|
||||
@ -1801,6 +1807,9 @@ addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object));
|
||||
System::Monitor*
|
||||
objectMonitor(Thread* t, object o);
|
||||
|
||||
void
|
||||
exit(Thread* t);
|
||||
|
||||
} // namespace vm
|
||||
|
||||
#endif//MACHINE_H
|
||||
|
35
src/main.cpp
35
src/main.cpp
@ -125,6 +125,28 @@ const bool Verbose = false;
|
||||
|
||||
class System: public vm::System {
|
||||
public:
|
||||
class Thread: public vm::System::Thread {
|
||||
public:
|
||||
Thread(vm::System* s, vm::System::Runnable* r): s(s), r(r) { }
|
||||
|
||||
virtual void run() {
|
||||
r->run(this);
|
||||
}
|
||||
|
||||
virtual void join() {
|
||||
int rv = pthread_join(thread, 0);
|
||||
assert(s, rv == 0);
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
s->free(this);
|
||||
}
|
||||
|
||||
vm::System* s;
|
||||
vm::System::Runnable* r;
|
||||
pthread_t thread;
|
||||
};
|
||||
|
||||
class Monitor: public vm::System::Monitor {
|
||||
public:
|
||||
Monitor(vm::System* s): s(s), context(0), depth(0) {
|
||||
@ -312,9 +334,16 @@ class System: public vm::System {
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
virtual Status start(Thread* t) {
|
||||
pthread_t thread;
|
||||
int rv = pthread_create(&thread, 0, run, t);
|
||||
virtual Status attach(vm::System::Thread** tp) {
|
||||
Thread* t = new (vm::System::allocate(sizeof(Thread))) Thread(this, 0);
|
||||
t->thread = pthread_self();
|
||||
*tp = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual Status start(Runnable* r) {
|
||||
Thread* t = new (vm::System::allocate(sizeof(Thread))) Thread(this, r);
|
||||
int rv = pthread_create(&(t->thread), 0, run, t);
|
||||
assert(this, rv == 0);
|
||||
return 0;
|
||||
}
|
||||
|
240
src/run.cpp
240
src/run.cpp
@ -65,8 +65,17 @@ make(Thread* t, object class_)
|
||||
unsigned sizeInBytes = pad(classFixedSize(t, class_));
|
||||
object instance = allocate(t, sizeInBytes);
|
||||
*static_cast<object*>(instance) = class_;
|
||||
memset(static_cast<object*>(instance) + sizeof(object), 0,
|
||||
memset(static_cast<object*>(instance) + 1, 0,
|
||||
sizeInBytes - sizeof(object));
|
||||
|
||||
fprintf(stderr, "new instance: %p\n", instance);
|
||||
|
||||
if (class_ == arrayBody(t, t->vm->types, Machine::ThreadType)) {
|
||||
if (threadPeer(t, instance)) {
|
||||
fprintf(stderr, "yo!\n");
|
||||
}
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@ -417,8 +426,8 @@ addInterfaces(Thread* t, object class_, object map)
|
||||
for (unsigned i = 0; i < arrayLength(t, table); i += increment) {
|
||||
object interface = arrayBody(t, table, i);
|
||||
object name = className(t, interface);
|
||||
hashMapInsertOrReplace(t, map, name, interface, byteArrayHash,
|
||||
byteArrayEqual);
|
||||
hashMapInsertMaybe(t, map, name, interface, byteArrayHash,
|
||||
byteArrayEqual);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -447,8 +456,7 @@ parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
|
||||
object interface = resolveClass(t, name);
|
||||
PROTECT(t, interface);
|
||||
|
||||
hashMapInsertOrReplace(t, map, name, interface, byteArrayHash,
|
||||
byteArrayEqual);
|
||||
hashMapInsertMaybe(t, map, name, interface, byteArrayHash, byteArrayEqual);
|
||||
|
||||
addInterfaces(t, interface, map);
|
||||
}
|
||||
@ -881,8 +889,8 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
object vtable = classVirtualTable(t, arrayBody(t, itable, i));
|
||||
for (unsigned j = 0; j < virtualCount; ++j) {
|
||||
object method = arrayBody(t, vtable, j);
|
||||
if (hashMapInsertOrReplace(t, virtualMap, method, method, methodHash,
|
||||
methodEqual))
|
||||
if (hashMapInsertMaybe(t, virtualMap, method, method, methodHash,
|
||||
methodEqual))
|
||||
{
|
||||
++ virtualCount;
|
||||
}
|
||||
@ -971,15 +979,19 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
methodOffset(t, method) = virtualCount++;
|
||||
|
||||
listAppend(t, newVirtuals, method);
|
||||
|
||||
hashMapInsert(t, virtualMap, method, method, methodHash);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & ACC_NATIVE) {
|
||||
object p = hashMapFindNode
|
||||
(t, nativeMap, method, methodHash, methodEqual);
|
||||
|
||||
if (p == 0) {
|
||||
hashMapInsert(t, virtualMap, method, method, methodHash);
|
||||
|
||||
if (p) {
|
||||
set(t, tripleSecond(t, p), method);
|
||||
} else {
|
||||
hashMapInsert(t, virtualMap, method, 0, methodHash);
|
||||
}
|
||||
}
|
||||
|
||||
@ -990,10 +1002,10 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
object method = arrayBody(t, methodTable, i);
|
||||
|
||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||
object p = hashMapFindNode
|
||||
object overloaded = hashMapFind
|
||||
(t, nativeMap, method, methodHash, methodEqual);
|
||||
|
||||
object jniName = makeJNIName(t, method, p != 0);
|
||||
object jniName = makeJNIName(t, method, overloaded);
|
||||
set(t, methodCode(t, method), jniName);
|
||||
}
|
||||
}
|
||||
@ -1023,10 +1035,10 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
set(t, arrayBody(t, vtable, i), method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) {
|
||||
set(t, arrayBody(t, vtable, i++), pairFirst(t, p));
|
||||
for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) {
|
||||
set(t, arrayBody(t, vtable, i++), pairFirst(t, p));
|
||||
}
|
||||
}
|
||||
|
||||
set(t, classVirtualTable(t, class_), vtable);
|
||||
@ -1046,6 +1058,7 @@ parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
||||
object method = arrayBody(t, ivtable, j);
|
||||
method = hashMapFind
|
||||
(t, virtualMap, method, methodHash, methodEqual);
|
||||
assert(t, method);
|
||||
|
||||
set(t, arrayBody(t, vtable, j), method);
|
||||
}
|
||||
@ -1368,11 +1381,26 @@ resolveNativeMethodData(Thread* t, object method)
|
||||
}
|
||||
|
||||
inline void
|
||||
checkStack(Thread* t, object method)
|
||||
{
|
||||
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
||||
unsigned base = t->sp - parameterFootprint;
|
||||
if (UNLIKELY(base
|
||||
+ codeMaxLocals(t, methodCode(t, method))
|
||||
+ FrameFootprint
|
||||
+ codeMaxStack(t, methodCode(t, method))
|
||||
> Thread::StackSizeInWords / 2))
|
||||
{
|
||||
t->exception = makeStackOverflowError(t);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
invokeNative(Thread* t, object method)
|
||||
{
|
||||
object data = resolveNativeMethodData(t, method);
|
||||
if (UNLIKELY(t->exception)) {
|
||||
return;
|
||||
return VoidField;
|
||||
}
|
||||
|
||||
pushFrame(t, method);
|
||||
@ -1419,7 +1447,8 @@ invokeNative(Thread* t, object method)
|
||||
void* function = nativeMethodDataFunction(t, data);
|
||||
|
||||
bool builtin = nativeMethodDataBuiltin(t, data);
|
||||
if (not builtin) {
|
||||
Thread::State oldState = t->state;
|
||||
if (not builtin) {
|
||||
enter(t, Thread::IdleState);
|
||||
}
|
||||
|
||||
@ -1432,13 +1461,13 @@ invokeNative(Thread* t, object method)
|
||||
returnType);
|
||||
|
||||
if (not builtin) {
|
||||
enter(t, Thread::ActiveState);
|
||||
enter(t, oldState);
|
||||
}
|
||||
|
||||
popFrame(t);
|
||||
|
||||
if (UNLIKELY(t->exception)) {
|
||||
return;
|
||||
return VoidField;
|
||||
}
|
||||
|
||||
switch (returnCode) {
|
||||
@ -1467,6 +1496,8 @@ invokeNative(Thread* t, object method)
|
||||
default:
|
||||
abort(t);
|
||||
};
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
object
|
||||
@ -1853,23 +1884,29 @@ run(Thread* t)
|
||||
case ByteField:
|
||||
case BooleanField:
|
||||
pushInt(t, cast<int8_t>(instance, fieldOffset(t, field)));
|
||||
break;
|
||||
|
||||
case CharField:
|
||||
case ShortField:
|
||||
pushInt(t, cast<int16_t>(instance, fieldOffset(t, field)));
|
||||
break;
|
||||
|
||||
case FloatField:
|
||||
case IntField:
|
||||
pushInt(t, cast<int32_t>(instance, fieldOffset(t, field)));
|
||||
break;
|
||||
|
||||
case DoubleField:
|
||||
case LongField:
|
||||
pushLong(t, cast<int64_t>(instance, fieldOffset(t, field)));
|
||||
break;
|
||||
|
||||
case ObjectField:
|
||||
pushObject(t, cast<object>(instance, fieldOffset(t, field)));
|
||||
break;
|
||||
|
||||
default: abort(t);
|
||||
default:
|
||||
abort(t);
|
||||
}
|
||||
} else {
|
||||
exception = makeNullPointerException(t);
|
||||
@ -3025,22 +3062,10 @@ run(Thread* t)
|
||||
invoke: {
|
||||
if (methodFlags(t, code) & ACC_NATIVE) {
|
||||
invokeNative(t, code);
|
||||
|
||||
if (UNLIKELY(exception)) {
|
||||
goto throw_;
|
||||
}
|
||||
if (UNLIKELY(exception)) goto throw_;
|
||||
} else {
|
||||
unsigned parameterFootprint = methodParameterFootprint(t, code);
|
||||
unsigned base = sp - parameterFootprint;
|
||||
if (UNLIKELY(base
|
||||
+ codeMaxLocals(t, methodCode(t, code))
|
||||
+ FrameFootprint
|
||||
+ codeMaxStack(t, methodCode(t, code))
|
||||
> Thread::StackSizeInWords / 2))
|
||||
{
|
||||
exception = makeStackOverflowError(t);
|
||||
goto throw_;
|
||||
}
|
||||
checkStack(t, code);
|
||||
if (UNLIKELY(exception)) goto throw_;
|
||||
|
||||
pushFrame(t, code);
|
||||
}
|
||||
@ -3048,6 +3073,10 @@ run(Thread* t)
|
||||
|
||||
throw_:
|
||||
for (; frame >= 0; frame = frameNext(t, frame)) {
|
||||
if (methodFlags(t, frameMethod(t, frame)) & ACC_NATIVE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
code = methodCode(t, frameMethod(t, frame));
|
||||
object eht = codeExceptionHandlerTable(t, code);
|
||||
if (eht) {
|
||||
@ -3131,50 +3160,137 @@ run(Thread* t)
|
||||
void
|
||||
run(Thread* t, const char* className, int argc, const char** argv)
|
||||
{
|
||||
enter(t, Thread::ActiveState);
|
||||
object args = makeObjectArray
|
||||
(t, arrayBody(t, t->vm->types, Machine::StringType), argc, true);
|
||||
|
||||
object class_ = resolveClass(t, makeByteArray(t, "%s", className));
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
PROTECT(t, class_);
|
||||
PROTECT(t, args);
|
||||
|
||||
object name = makeByteArray(t, "main");
|
||||
PROTECT(t, name);
|
||||
|
||||
object spec = makeByteArray(t, "([Ljava/lang/String;)V");
|
||||
object reference = makeReference(t, class_, name, spec);
|
||||
|
||||
object method = findMethodInClass(t, class_, reference);
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
object args = makeObjectArray
|
||||
(t, arrayBody(t, t->vm->types, Machine::StringType), argc, true);
|
||||
|
||||
PROTECT(t, args);
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
object arg = makeString(t, "%s", argv);
|
||||
set(t, objectArrayBody(t, args, i), arg);
|
||||
}
|
||||
|
||||
pushObject(t, args);
|
||||
pushFrame(t, method);
|
||||
}
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
object arg = makeString(t, "%s", argv);
|
||||
set(t, objectArrayBody(t, args, i), arg);
|
||||
}
|
||||
|
||||
run(t);
|
||||
run(t, className, "main", "([Ljava/lang/String;)V", args);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace vm {
|
||||
|
||||
object
|
||||
run(Thread* t, const char* className, const char* methodName,
|
||||
const char* methodSpec, ...)
|
||||
{
|
||||
enter(t, Thread::ActiveState);
|
||||
|
||||
object class_ = resolveClass(t, makeByteArray(t, "%s", className));
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
PROTECT(t, class_);
|
||||
|
||||
object name = makeByteArray(t, methodName);
|
||||
PROTECT(t, name);
|
||||
|
||||
object spec = makeByteArray(t, methodSpec);
|
||||
object reference = makeReference(t, class_, name, spec);
|
||||
|
||||
object method = findMethodInClass(t, class_, reference);
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
va_list a;
|
||||
va_start(a, methodSpec);
|
||||
|
||||
if ((methodFlags(t, method) & ACC_STATIC) == 0) {
|
||||
pushObject(t, va_arg(a, object));
|
||||
}
|
||||
|
||||
const char* s = methodSpec;
|
||||
++ s; // skip '('
|
||||
while (*s and *s != ')') {
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
pushObject(t, va_arg(a, object));
|
||||
break;
|
||||
|
||||
case '[':
|
||||
while (*s == '[') ++ s;
|
||||
switch (*s) {
|
||||
case 'L':
|
||||
while (*s and *s != ';') ++ s;
|
||||
++ s;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
break;
|
||||
}
|
||||
pushObject(t, va_arg(a, object));
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
case 'D':
|
||||
++ s;
|
||||
pushLong(t, va_arg(a, uint64_t));
|
||||
break;
|
||||
|
||||
default:
|
||||
++ s;
|
||||
pushInt(t, va_arg(a, uint32_t));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(a);
|
||||
|
||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||
unsigned returnCode = invokeNative(t, method);
|
||||
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
switch (returnCode) {
|
||||
case ByteField:
|
||||
case BooleanField:
|
||||
case CharField:
|
||||
case ShortField:
|
||||
case FloatField:
|
||||
case IntField:
|
||||
return makeInt(t, popInt(t));
|
||||
|
||||
case LongField:
|
||||
case DoubleField:
|
||||
return makeLong(t, popLong(t));
|
||||
|
||||
case ObjectField:
|
||||
return popObject(t);
|
||||
|
||||
case VoidField:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
abort(t);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
checkStack(t, method);
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
pushFrame(t, method);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ::run(t);
|
||||
}
|
||||
|
||||
void
|
||||
run(System* system, Heap* heap, ClassFinder* classFinder,
|
||||
const char* className, int argc, const char** argv)
|
||||
{
|
||||
Machine m(system, heap, classFinder);
|
||||
Thread t(&m);
|
||||
Thread t(&m, 0, 0, 0);
|
||||
|
||||
::run(&t, className, argc, argv);
|
||||
|
||||
exit(&t);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,9 +4,14 @@
|
||||
#include "system.h"
|
||||
#include "heap.h"
|
||||
#include "class-finder.h"
|
||||
#include "machine.h"
|
||||
|
||||
namespace vm {
|
||||
|
||||
object
|
||||
run(Thread* t, const char* className, const char* methodName,
|
||||
const char* methodSpec, ...);
|
||||
|
||||
void
|
||||
run(System* sys, Heap* heap, ClassFinder* classFinder,
|
||||
const char* className, int argc, const char** argv);
|
||||
|
25
src/system.h
25
src/system.h
@ -5,7 +5,15 @@
|
||||
|
||||
namespace vm {
|
||||
|
||||
class System {
|
||||
class Allocator {
|
||||
public:
|
||||
virtual ~Allocator() { }
|
||||
virtual void* tryAllocate(unsigned size) = 0;
|
||||
virtual void* allocate(unsigned size) = 0;
|
||||
virtual void free(const void*) = 0;
|
||||
};
|
||||
|
||||
class System: public Allocator {
|
||||
public:
|
||||
typedef intptr_t Status;
|
||||
|
||||
@ -13,6 +21,14 @@ class System {
|
||||
public:
|
||||
virtual ~Thread() { }
|
||||
virtual void run() = 0;
|
||||
virtual void join() = 0;
|
||||
virtual void dispose() = 0;
|
||||
};
|
||||
|
||||
class Runnable {
|
||||
public:
|
||||
virtual ~Runnable() { }
|
||||
virtual void run(Thread*) = 0;
|
||||
};
|
||||
|
||||
class Monitor {
|
||||
@ -38,9 +54,8 @@ class System {
|
||||
virtual ~System() { }
|
||||
|
||||
virtual bool success(Status) = 0;
|
||||
virtual void* tryAllocate(unsigned size) = 0;
|
||||
virtual void free(const void*) = 0;
|
||||
virtual Status start(Thread*) = 0;
|
||||
virtual Status attach(Thread**) = 0;
|
||||
virtual Status start(Runnable*) = 0;
|
||||
virtual Status make(Monitor**) = 0;
|
||||
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
||||
unsigned count, unsigned size,
|
||||
@ -48,7 +63,7 @@ class System {
|
||||
virtual Status load(Library**, const char* name, Library* next) = 0;
|
||||
virtual void abort() = 0;
|
||||
|
||||
void* allocate(unsigned size) {
|
||||
virtual void* allocate(unsigned size) {
|
||||
void* p = tryAllocate(size);
|
||||
if (p == 0) {
|
||||
abort();
|
||||
|
@ -143,6 +143,11 @@
|
||||
(int32_t length)
|
||||
(int32_t hash))
|
||||
|
||||
(type thread java/lang/Thread
|
||||
(extends jobject)
|
||||
(object task)
|
||||
(int64_t peer))
|
||||
|
||||
(type throwable java/lang/Throwable
|
||||
(extends jobject)
|
||||
(object message)
|
||||
@ -158,6 +163,9 @@
|
||||
(type nullPointerException java/lang/NullPointerException
|
||||
(extends runtimeException))
|
||||
|
||||
(type illegalStateException java/lang/IllegalStateException
|
||||
(extends runtimeException))
|
||||
|
||||
(type arrayIndexOutOfBoundsException
|
||||
java/lang/ArrayIndexOutOfBoundsException
|
||||
(extends runtimeException))
|
||||
|
Loading…
x
Reference in New Issue
Block a user