corda/src/machine.cpp

2918 lines
72 KiB
C++
Raw Normal View History

/* Copyright (c) 2008, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
2007-07-06 23:50:26 +00:00
#include "jnienv.h"
#include "machine.h"
2007-11-26 23:15:53 +00:00
#include "util.h"
#include "stream.h"
#include "constants.h"
#include "processor.h"
2007-07-06 23:50:26 +00:00
using namespace vm;
namespace {
2007-07-07 18:09:16 +00:00
bool
find(Thread* t, Thread* o)
{
return (t == o)
or (t->peer and find(t->peer, o))
or (t->child and find(t->child, o));
2007-07-07 18:09:16 +00:00
}
void
join(Thread* t, Thread* o)
{
if (t != o) {
o->systemThread->join();
2007-07-18 01:33:00 +00:00
o->state = Thread::JoinedState;
2007-07-07 18:09:16 +00:00
}
}
2007-11-27 22:23:00 +00:00
unsigned
count(Thread* t, Thread* o)
{
unsigned c = 0;
if (t != o) ++ c;
if (t->peer) c += count(t->peer, o);
2007-11-27 22:23:00 +00:00
if (t->child) c += count(t->child, o);
return c;
}
Thread**
fill(Thread* t, Thread* o, Thread** array)
{
if (t != o) *(array++) = t;
if (t->peer) fill(t->peer, o, array);
if (t->child) fill(t->child, o, array);
2007-11-27 22:23:00 +00:00
return array;
}
2007-07-07 18:09:16 +00:00
void
dispose(Thread* t, Thread* o, bool remove)
{
if (remove) {
2007-11-27 22:23:00 +00:00
// debug
expect(t, find(t->m->rootThread, o));
unsigned c = count(t->m->rootThread, o);
Thread* threads[c];
fill(t->m->rootThread, o, threads);
// end debug
2007-07-07 18:09:16 +00:00
if (o->parent) {
2007-11-27 23:04:15 +00:00
Thread* previous = 0;
2007-11-27 22:23:00 +00:00
for (Thread* p = o->parent->child; p;) {
if (p == o) {
if (p == o->parent->child) {
o->parent->child = p->peer;
} else {
previous->peer = p->peer;
}
break;
} else {
previous = p;
p = p->peer;
2007-07-07 18:09:16 +00:00
}
2007-11-27 22:23:00 +00:00
}
for (Thread* p = o->child; p;) {
Thread* next = p->peer;
p->peer = o->parent->child;
o->parent->child = p;
p->parent = o->parent;
p = next;
2007-07-07 18:09:16 +00:00
}
} else if (o->child) {
t->m->rootThread = o->child;
2007-11-27 22:23:00 +00:00
for (Thread* p = o->peer; p;) {
Thread* next = p->peer;
p->peer = t->m->rootThread;
t->m->rootThread = p;
p = next;
}
2007-07-07 18:09:16 +00:00
} else if (o->peer) {
t->m->rootThread = o->peer;
2007-07-07 18:09:16 +00:00
} else {
abort(t);
}
2007-11-27 22:23:00 +00:00
// debug
expect(t, not find(t->m->rootThread, o));
for (unsigned i = 0; i < c; ++i) {
expect(t, find(t->m->rootThread, threads[i]));
}
// end debug
2007-07-07 18:09:16 +00:00
}
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);
}
2007-07-18 01:33:00 +00:00
switch (o->state) {
case Thread::ZombieState:
2007-07-07 18:09:16 +00:00
join(t, o);
2007-07-18 01:33:00 +00:00
// fall through
case Thread::JoinedState:
2007-07-07 18:09:16 +00:00
dispose(t, o, true);
2007-07-18 01:33:00 +00:00
default: break;
2007-07-07 18:09:16 +00:00
}
}
unsigned
footprint(Thread* t)
{
unsigned n = t->heapOffset + t->heapIndex;
for (Thread* c = t->child; c; c = c->peer) {
n += footprint(c);
}
return n;
}
2007-07-07 23:47:35 +00:00
void
visitRoots(Thread* t, Heap::Visitor* v)
{
if (t->state != Thread::ZombieState) {
v->visit(&(t->javaThread));
v->visit(&(t->exception));
2007-07-07 23:47:35 +00:00
t->m->processor->visitObjects(t, v);
2007-07-07 23:47:35 +00:00
for (Thread::Protector* p = t->protector; p; p = p->next) {
p->visit(v);
2007-07-07 23:47:35 +00:00
}
}
for (Thread* c = t->child; c; c = c->peer) {
visitRoots(c, v);
}
}
void
2007-11-02 14:15:06 +00:00
walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize,
unsigned arrayElementSize, unsigned arrayLength)
{
unsigned fixedSizeInWords = ceiling(fixedSize, BytesPerWord);
unsigned arrayElementSizeInWords
= ceiling(arrayElementSize, BytesPerWord);
for (unsigned i = 0; i < fixedSizeInWords; ++i) {
if (mask[i / 32] & (static_cast<uint32_t>(1) << (i % 32))) {
if (not w->visit(i)) {
return;
}
}
}
bool arrayObjectElements = false;
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
unsigned k = fixedSizeInWords + j;
if (mask[k / 32] & (static_cast<uint32_t>(1) << (k % 32))) {
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[k / 32] & (static_cast<uint32_t>(1) << (k % 32))) {
if (not w->visit
(fixedSizeInWords + (i * arrayElementSizeInWords) + j))
{
return;
}
}
}
}
}
}
void
walk(Thread* t, Heap::Walker* w, object o)
2007-10-28 01:54:30 +00:00
{
object class_ = static_cast<object>(t->m->heap->follow(objectClass(t, o)));
object objectMask = static_cast<object>
(t->m->heap->follow(classObjectMask(t, class_)));
if (objectMask) {
unsigned fixedSize = classFixedSize(t, class_);
unsigned arrayElementSize = classArrayElementSize(t, class_);
unsigned arrayLength
= (arrayElementSize ?
cast<uintptr_t>(o, fixedSize - BytesPerWord) : 0);
2007-11-02 14:15:06 +00:00
uint32_t mask[intArrayLength(t, objectMask)];
2007-10-28 01:54:30 +00:00
memcpy(mask, &intArrayBody(t, objectMask, 0),
intArrayLength(t, objectMask) * 4);
2007-11-02 14:15:06 +00:00
walk(t, w, mask, fixedSize, arrayElementSize, arrayLength);
2007-11-02 21:08:14 +00:00
} else if (classVmFlags(t, class_) & SingletonFlag) {
unsigned length = singletonLength(t, o);
if (length) {
walk(t, w, singletonMask(t, o),
(singletonCount(t, o) + 2) * BytesPerWord, 0, 0);
2007-11-02 21:08:14 +00:00
} else {
w->visit(0);
}
2007-10-28 01:54:30 +00:00
} else {
w->visit(0);
}
}
void
finalizerTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
{
v->visit(&finalizerTarget(t, *p));
object finalizer = *p;
*p = finalizerNext(t, finalizer);
finalizerNext(t, finalizer) = t->m->finalizeQueue;
t->m->finalizeQueue = finalizer;
}
2007-07-20 01:07:30 +00:00
void
2007-10-28 01:54:30 +00:00
referenceTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
2007-07-20 01:07:30 +00:00
{
if (DebugReferences) {
fprintf(stderr, "target %p unreachable for reference %p\n",
jreferenceTarget(t, *p), *p);
}
v->visit(p);
2007-07-20 01:07:30 +00:00
jreferenceTarget(t, *p) = 0;
if (jreferenceQueue(t, *p)
and t->m->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable)
{
2007-07-20 01:07:30 +00:00
// queue is reachable - add the reference
v->visit(&jreferenceQueue(t, *p));
2007-07-20 01:07:30 +00:00
object q = jreferenceQueue(t, *p);
set(t, *p, JreferenceJNext, *p);
2007-07-20 01:07:30 +00:00
if (referenceQueueFront(t, q)) {
set(t, referenceQueueRear(t, q), JreferenceJNext, *p);
2007-07-20 01:07:30 +00:00
} else {
set(t, q, ReferenceQueueFront, *p);
2007-07-20 01:07:30 +00:00
}
set(t, q, ReferenceQueueRear, *p);
2007-07-20 01:07:30 +00:00
jreferenceQueue(t, *p) = 0;
}
*p = jreferenceVmNext(t, *p);
2007-07-20 01:07:30 +00:00
}
void
2007-10-28 01:54:30 +00:00
referenceUnreachable(Thread* t, Heap::Visitor* v, object* p)
{
if (DebugReferences) {
fprintf(stderr, "reference %p unreachable (target %p)\n",
*p, jreferenceTarget(t, *p));
}
if (jreferenceQueue(t, *p)
and t->m->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable)
{
// queue is reachable - add the reference
2007-10-28 01:54:30 +00:00
referenceTargetUnreachable(t, v, p);
} else {
*p = jreferenceVmNext(t, *p);
}
}
2007-07-20 01:07:30 +00:00
void
2007-10-28 01:54:30 +00:00
referenceTargetReachable(Thread* t, Heap::Visitor* v, object* p)
2007-07-20 01:07:30 +00:00
{
if (DebugReferences) {
fprintf(stderr, "target %p reachable for reference %p\n",
jreferenceTarget(t, *p), *p);
}
v->visit(p);
v->visit(&jreferenceTarget(t, *p));
2007-07-20 01:07:30 +00:00
if (t->m->heap->status(jreferenceQueue(t, *p)) == Heap::Unreachable) {
2007-07-20 01:07:30 +00:00
jreferenceQueue(t, *p) = 0;
} else {
v->visit(&jreferenceQueue(t, *p));
2007-07-20 01:07:30 +00:00
}
}
void
postVisit(Thread* t, Heap::Visitor* v)
{
Machine* m = t->m;
2007-10-28 01:54:30 +00:00
bool major = m->heap->collectionType() == Heap::MajorCollection;
for (object* p = &(m->finalizeQueue); *p; p = &(finalizerNext(t, *p))) {
v->visit(p);
v->visit(&finalizerTarget(t, *p));
}
for (object* p = &(m->finalizeQueue); *p; p = &(finalizerNext(t, *p))) {
v->visit(p);
v->visit(&finalizerTarget(t, *p));
}
object firstNewTenuredFinalizer = 0;
object lastNewTenuredFinalizer = 0;
for (object* p = &(m->finalizers); *p;) {
v->visit(p);
if (m->heap->status(finalizerTarget(t, *p)) == Heap::Unreachable) {
// target is unreachable - queue it up for finalization
2007-10-28 01:54:30 +00:00
finalizerTargetUnreachable(t, v, p);
} else {
// target is reachable
v->visit(&finalizerTarget(t, *p));
if (m->heap->status(*p) == Heap::Tenured) {
// the finalizer is tenured, so we remove it from
// m->finalizers and later add it to m->tenuredFinalizers
if (lastNewTenuredFinalizer == 0) {
lastNewTenuredFinalizer = *p;
}
object finalizer = *p;
*p = finalizerNext(t, finalizer);
finalizerNext(t, finalizer) = firstNewTenuredFinalizer;
firstNewTenuredFinalizer = finalizer;
} else {
p = &finalizerNext(t, *p);
}
}
}
object firstNewTenuredWeakReference = 0;
object lastNewTenuredWeakReference = 0;
for (object* p = &(m->weakReferences); *p;) {
if (m->heap->status(*p) == Heap::Unreachable) {
// reference is unreachable
2007-10-28 01:54:30 +00:00
referenceUnreachable(t, v, p);
2007-08-14 01:44:47 +00:00
} else if (m->heap->status(jreferenceTarget(t, *p))
2007-08-14 00:37:00 +00:00
== Heap::Unreachable)
{
// target is unreachable
2007-10-28 01:54:30 +00:00
referenceTargetUnreachable(t, v, p);
} else {
// both reference and target are reachable
2007-10-28 01:54:30 +00:00
referenceTargetReachable(t, v, p);
if (m->heap->status(*p) == Heap::Tenured) {
// the reference is tenured, so we remove it from
// m->weakReferences and later add it to
// m->tenuredWeakReferences
if (lastNewTenuredWeakReference == 0) {
lastNewTenuredWeakReference = *p;
}
object reference = *p;
*p = jreferenceVmNext(t, reference);
jreferenceVmNext(t, reference) = firstNewTenuredWeakReference;
firstNewTenuredWeakReference = reference;
} else {
p = &jreferenceVmNext(t, *p);
}
}
}
2007-10-28 01:54:30 +00:00
if (major) {
for (object* p = &(m->tenuredFinalizers); *p;) {
v->visit(p);
if (m->heap->status(finalizerTarget(t, *p)) == Heap::Unreachable) {
// target is unreachable - queue it up for finalization
2007-10-28 01:54:30 +00:00
finalizerTargetUnreachable(t, v, p);
} else {
// target is reachable
v->visit(&finalizerTarget(t, *p));
p = &finalizerNext(t, *p);
}
}
for (object* p = &(m->tenuredWeakReferences); *p;) {
if (m->heap->status(*p) == Heap::Unreachable) {
// reference is unreachable
2007-10-28 01:54:30 +00:00
referenceUnreachable(t, v, p);
2007-08-14 01:44:47 +00:00
} else if (m->heap->status(jreferenceTarget(t, *p))
== Heap::Unreachable)
{
// target is unreachable
2007-10-28 01:54:30 +00:00
referenceTargetUnreachable(t, v, p);
} else {
// both reference and target are reachable
2007-10-28 01:54:30 +00:00
referenceTargetReachable(t, v, p);
p = &jreferenceVmNext(t, *p);
}
}
}
if (lastNewTenuredFinalizer) {
finalizerNext(t, lastNewTenuredFinalizer) = m->tenuredFinalizers;
m->tenuredFinalizers = firstNewTenuredFinalizer;
}
if (lastNewTenuredWeakReference) {
jreferenceVmNext(t, lastNewTenuredWeakReference) = m->tenuredWeakReferences;
m->tenuredWeakReferences = firstNewTenuredWeakReference;
}
}
2007-07-07 23:47:35 +00:00
void
postCollect(Thread* t)
{
#ifdef VM_STRESS
2008-04-13 18:15:04 +00:00
t->m->heap->free(t->defaultHeap, Thread::HeapSizeInBytes);
2007-09-13 03:15:16 +00:00
t->defaultHeap = static_cast<uintptr_t*>
2008-04-13 18:15:04 +00:00
(t->m->heap->allocate(Thread::HeapSizeInBytes));
#endif
t->heap = t->defaultHeap;
t->heapOffset = 0;
t->heapIndex = 0;
2007-07-07 23:47:35 +00:00
2008-04-09 19:08:13 +00:00
if (t->backupHeap) {
t->m->heap->free
2008-04-13 18:15:04 +00:00
(t->backupHeap, t->backupHeapSizeInWords * BytesPerWord);
t->backupHeap = 0;
2008-04-09 19:08:13 +00:00
t->backupHeapIndex = 0;
t->backupHeapSizeInWords = 0;
}
2007-07-07 23:47:35 +00:00
for (Thread* c = t->child; c; c = c->peer) {
postCollect(c);
}
}
2007-07-06 23:50:26 +00:00
object
makeByteArray(Thread* t, const char* format, va_list a)
{
const int Size = 256;
2007-07-06 23:50:26 +00:00
char buffer[Size];
int r = vsnprintf(buffer, Size - 1, format, a);
expect(t, r >= 0 and r < Size - 1);
2007-07-06 23:50:26 +00:00
object s = makeByteArray(t, strlen(buffer) + 1, false);
memcpy(&byteArrayBody(t, s, 0), buffer, byteArrayLength(t, s));
return s;
}
object
parseUtf8(Thread* t, Stream& s, unsigned length)
{
object value = makeByteArray(t, length + 1, false);
unsigned vi = 0;
2007-10-24 23:05:14 +00:00
for (unsigned si = 0; si < length; ++si) {
unsigned a = s.read1();
if (a & 0x80) {
// todo: handle non-ASCII characters properly
if (a & 0x20) {
// 3 bytes
si += 2;
assert(t, si < length);
/*unsigned b = */s.read1();
/*unsigned c = */s.read1();
byteArrayBody(t, value, vi++) = '_';
} else {
// 2 bytes
++ si;
assert(t, si < length);
unsigned b = s.read1();
if (a == 0xC0 and b == 0x80) {
byteArrayBody(t, value, vi++) = 0;
} else {
byteArrayBody(t, value, vi++) = '_';
}
}
} else {
2007-10-24 23:05:14 +00:00
byteArrayBody(t, value, vi++) = a;
}
}
if (vi < length) {
PROTECT(t, value);
object v = makeByteArray(t, vi + 1, false);
memcpy(&byteArrayBody(t, v, 0), &byteArrayBody(t, value, 0), vi);
value = v;
}
byteArrayBody(t, value, vi) = 0;
return value;
}
unsigned
parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i)
{
PROTECT(t, pool);
s.setPosition(index[i]);
switch (s.read1()) {
case CONSTANT_Integer:
case CONSTANT_Float: {
singletonValue(t, pool, i) = s.read4();
} return 1;
case CONSTANT_Long:
case CONSTANT_Double: {
uint64_t v = s.read8();
memcpy(&singletonValue(t, pool, i), &v, 8);
} return 2;
case CONSTANT_Utf8: {
if (singletonObject(t, pool, i) == 0) {
object value = parseUtf8(t, s, s.read2());
set(t, pool, SingletonBody + (i * BytesPerWord), value);
}
} return 1;
case CONSTANT_Class: {
if (singletonObject(t, pool, i) == 0) {
unsigned si = s.read2() - 1;
parsePoolEntry(t, s, index, pool, si);
object value = singletonObject(t, pool, si);
set(t, pool, SingletonBody + (i * BytesPerWord), value);
}
} return 1;
case CONSTANT_String: {
if (singletonObject(t, pool, i) == 0) {
unsigned si = s.read2() - 1;
parsePoolEntry(t, s, index, pool, si);
object value = singletonObject(t, pool, si);
value = makeString(t, value, 0, byteArrayLength(t, value) - 1, 0);
value = intern(t, value);
set(t, pool, SingletonBody + (i * BytesPerWord), value);
}
} return 1;
case CONSTANT_NameAndType: {
if (singletonObject(t, pool, i) == 0) {
unsigned ni = s.read2() - 1;
unsigned ti = s.read2() - 1;
parsePoolEntry(t, s, index, pool, ni);
parsePoolEntry(t, s, index, pool, ti);
object name = singletonObject(t, pool, ni);
object type = singletonObject(t, pool, ti);
object value = makePair(t, name, type);
set(t, pool, SingletonBody + (i * BytesPerWord), value);
}
} return 1;
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref: {
if (singletonObject(t, pool, i) == 0) {
unsigned ci = s.read2() - 1;
unsigned nti = s.read2() - 1;
parsePoolEntry(t, s, index, pool, ci);
parsePoolEntry(t, s, index, pool, nti);
object class_ = singletonObject(t, pool, ci);
object nameAndType = singletonObject(t, pool, nti);
object value = makeReference
(t, class_, pairFirst(t, nameAndType), pairSecond(t, nameAndType));
set(t, pool, SingletonBody + (i * BytesPerWord), value);
}
} return 1;
default: abort(t);
}
}
object
parsePool(Thread* t, Stream& s)
{
unsigned count = s.read2() - 1;
object pool = makeSingleton(t, count);
PROTECT(t, pool);
if (count) {
2008-04-13 18:15:04 +00:00
uint32_t* index = static_cast<uint32_t*>(t->m->heap->allocate(count * 4));
for (unsigned i = 0; i < count; ++i) {
index[i] = s.position();
switch (s.read1()) {
case CONSTANT_Class:
case CONSTANT_String:
singletonMarkObject(t, pool, i);
s.skip(2);
break;
case CONSTANT_Integer:
case CONSTANT_Float:
s.skip(4);
break;
case CONSTANT_NameAndType:
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
singletonMarkObject(t, pool, i);
s.skip(4);
break;
case CONSTANT_Long:
case CONSTANT_Double:
s.skip(8);
++ i;
break;
case CONSTANT_Utf8:
singletonMarkObject(t, pool, i);
s.skip(s.read2());
break;
default: abort(t);
}
}
unsigned end = s.position();
for (unsigned i = 0; i < count;) {
i += parsePoolEntry(t, s, index, pool, i);
}
2008-04-13 18:15:04 +00:00
t->m->heap->free(index, count * 4);
s.setPosition(end);
}
return pool;
}
void
addInterfaces(Thread* t, object class_, object map)
{
object table = classInterfaceTable(t, class_);
if (table) {
unsigned increment = 2;
if (classFlags(t, class_) & ACC_INTERFACE) {
increment = 1;
}
PROTECT(t, map);
PROTECT(t, table);
for (unsigned i = 0; i < arrayLength(t, table); i += increment) {
object interface = arrayBody(t, table, i);
object name = className(t, interface);
hashMapInsertMaybe(t, map, name, interface, byteArrayHash,
byteArrayEqual);
}
}
}
void
parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
{
PROTECT(t, class_);
PROTECT(t, pool);
object map = makeHashMap(t, 0, 0);
PROTECT(t, map);
if (classSuper(t, class_)) {
addInterfaces(t, classSuper(t, class_), map);
}
2007-11-27 22:23:00 +00:00
unsigned count = s.read2();
for (unsigned i = 0; i < count; ++i) {
object name = singletonObject(t, pool, s.read2() - 1);
PROTECT(t, name);
object interface = resolveClass(t, name);
PROTECT(t, interface);
hashMapInsertMaybe(t, map, name, interface, byteArrayHash, byteArrayEqual);
addInterfaces(t, interface, map);
}
object interfaceTable = 0;
if (hashMapSize(t, map)) {
unsigned length = hashMapSize(t, map) ;
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
length *= 2;
}
interfaceTable = makeArray(t, length, true);
PROTECT(t, interfaceTable);
unsigned i = 0;
object it = hashMapIterator(t, map);
PROTECT(t, it);
for (; it; it = hashMapIteratorNext(t, it)) {
object interface = resolveClass
(t, tripleFirst(t, hashMapIteratorNode(t, it)));
if (UNLIKELY(t->exception)) return;
set(t, interfaceTable, ArrayBody + (i * BytesPerWord), interface);
++ i;
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
2007-08-14 00:37:00 +00:00
if (classVirtualTable(t, interface)) {
// we'll fill in this table in parseMethodTable():
object vtable = makeArray
(t, arrayLength(t, classVirtualTable(t, interface)), true);
set(t, interfaceTable, ArrayBody + (i * BytesPerWord), vtable);
2007-08-14 00:37:00 +00:00
}
++i;
}
}
}
set(t, class_, ClassInterfaceTable, interfaceTable);
}
void
parseFieldTable(Thread* t, Stream& s, object class_, object pool)
{
PROTECT(t, class_);
PROTECT(t, pool);
unsigned memberOffset = BytesPerWord;
if (classSuper(t, class_)) {
memberOffset = classFixedSize(t, classSuper(t, class_));
}
unsigned count = s.read2();
if (count) {
2007-11-02 21:08:14 +00:00
unsigned staticOffset = BytesPerWord * 2;
unsigned staticCount = 0;
object fieldTable = makeArray(t, count, true);
PROTECT(t, fieldTable);
2007-11-06 15:29:05 +00:00
object staticValueTable = makeIntArray(t, count, false);
PROTECT(t, staticValueTable);
2007-11-02 21:08:14 +00:00
uint8_t staticTypes[count];
for (unsigned i = 0; i < count; ++i) {
unsigned flags = s.read2();
unsigned name = s.read2();
unsigned spec = s.read2();
2007-11-06 15:29:05 +00:00
unsigned value = 0;
unsigned code = fieldCode
(t, byteArrayBody(t, singletonObject(t, pool, spec - 1), 0));
unsigned attributeCount = s.read2();
for (unsigned j = 0; j < attributeCount; ++j) {
object name = singletonObject(t, pool, s.read2() - 1);
unsigned length = s.read4();
if (strcmp(reinterpret_cast<const int8_t*>("ConstantValue"),
&byteArrayBody(t, name, 0)) == 0)
{
2007-11-06 15:29:05 +00:00
value = s.read2();
} else {
s.skip(length);
}
}
object field = makeField
(t,
0, // vm flags
2007-11-02 21:08:14 +00:00
code,
flags,
0, // offset
singletonObject(t, pool, name - 1),
singletonObject(t, pool, spec - 1),
class_);
if (flags & ACC_STATIC) {
2007-11-02 21:08:14 +00:00
unsigned size = fieldSize(t, code);
unsigned excess = (staticOffset % size) % BytesPerWord;
2007-11-02 21:08:14 +00:00
if (excess) {
staticOffset += BytesPerWord - excess;
}
fieldOffset(t, field) = staticOffset;
staticOffset += size;
2007-11-06 15:29:05 +00:00
intArrayBody(t, staticValueTable, staticCount) = value;
2007-11-02 21:08:14 +00:00
staticTypes[staticCount++] = code;
} else {
if (value) {
abort(t); // todo: handle non-static field initializers
}
unsigned excess = (memberOffset % fieldSize(t, code)) % BytesPerWord;
if (excess) {
memberOffset += BytesPerWord - excess;
}
fieldOffset(t, field) = memberOffset;
2007-11-02 21:08:14 +00:00
memberOffset += fieldSize(t, code);
}
set(t, fieldTable, ArrayBody + (i * BytesPerWord), field);
}
set(t, class_, ClassFieldTable, fieldTable);
2007-11-02 21:08:14 +00:00
if (staticCount) {
unsigned footprint = ceiling(staticOffset - (BytesPerWord * 2),
BytesPerWord);
object staticTable = makeSingleton(t, footprint);
2007-11-02 21:08:14 +00:00
uint8_t* body = reinterpret_cast<uint8_t*>
(&singletonBody(t, staticTable, 0));
for (unsigned i = 0, offset = 0; i < staticCount; ++i) {
unsigned size = fieldSize(t, staticTypes[i]);
unsigned excess = offset % size;
if (excess) {
offset += BytesPerWord - excess;
}
2007-11-06 15:29:05 +00:00
unsigned value = intArrayBody(t, staticValueTable, i);
2007-11-02 21:08:14 +00:00
if (value) {
switch (staticTypes[i]) {
case ByteField:
case BooleanField:
2007-11-06 15:29:05 +00:00
body[offset] = singletonValue(t, pool, value - 1);
2007-11-02 21:08:14 +00:00
break;
case CharField:
case ShortField:
2007-11-06 15:29:05 +00:00
*reinterpret_cast<uint16_t*>(body + offset)
= singletonValue(t, pool, value - 1);
2007-11-02 21:08:14 +00:00
break;
case IntField:
case FloatField:
2007-11-06 15:29:05 +00:00
*reinterpret_cast<uint32_t*>(body + offset)
= singletonValue(t, pool, value - 1);
2007-11-02 21:08:14 +00:00
break;
case LongField:
case DoubleField:
2007-11-06 15:29:05 +00:00
memcpy(body + offset, &singletonValue(t, pool, value - 1), 8);
2007-11-02 21:08:14 +00:00
break;
case ObjectField:
2007-11-06 15:29:05 +00:00
memcpy(body + offset,
&singletonObject(t, pool, value - 1),
BytesPerWord);
2007-11-02 21:08:14 +00:00
break;
default: abort(t);
}
} else {
memset(body + offset, 0, size);
}
if (staticTypes[i] == ObjectField) {
singletonMarkObject(t, staticTable, offset / BytesPerWord);
2007-11-02 21:08:14 +00:00
}
offset += size;
}
set(t, class_, ClassStaticTable, staticTable);
}
}
classFixedSize(t, class_) = pad(memberOffset);
if (classSuper(t, class_)
and memberOffset == classFixedSize(t, classSuper(t, class_)))
{
set(t, class_, ClassObjectMask,
classObjectMask(t, classSuper(t, class_)));
} else {
object mask = makeIntArray
(t, ceiling(classFixedSize(t, class_), 32 * BytesPerWord), true);
intArrayBody(t, mask, 0) = 1;
2007-08-14 00:37:00 +00:00
object superMask = 0;
if (classSuper(t, class_)) {
superMask = classObjectMask(t, classSuper(t, class_));
if (superMask) {
memcpy(&intArrayBody(t, mask, 0),
&intArrayBody(t, superMask, 0),
ceiling(classFixedSize(t, classSuper(t, class_)),
32 * BytesPerWord)
2007-08-14 00:37:00 +00:00
* 4);
}
}
bool sawReferenceField = false;
2007-08-14 00:37:00 +00:00
object fieldTable = classFieldTable(t, class_);
if (fieldTable) {
for (int i = arrayLength(t, fieldTable) - 1; i >= 0; --i) {
object field = arrayBody(t, fieldTable, i);
if ((fieldFlags(t, field) & ACC_STATIC) == 0
and fieldCode(t, field) == ObjectField)
{
unsigned index = fieldOffset(t, field) / BytesPerWord;
intArrayBody(t, mask, (index / 32)) |= 1 << (index % 32);
sawReferenceField = true;
}
}
}
2007-08-14 00:37:00 +00:00
if (superMask or sawReferenceField) {
set(t, class_, ClassObjectMask, mask);
}
}
}
object
parseCode(Thread* t, Stream& s, object pool)
{
2007-07-19 23:45:44 +00:00
PROTECT(t, pool);
unsigned maxStack = s.read2();
unsigned maxLocals = s.read2();
unsigned length = s.read4();
object code = makeCode(t, pool, 0, 0, maxStack, maxLocals, length, false);
s.read(&codeBody(t, code, 0), length);
PROTECT(t, code);
unsigned ehtLength = s.read2();
if (ehtLength) {
object eht = makeExceptionHandlerTable(t, ehtLength, false);
for (unsigned i = 0; i < ehtLength; ++i) {
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
exceptionHandlerStart(eh) = s.read2();
exceptionHandlerEnd(eh) = s.read2();
exceptionHandlerIp(eh) = s.read2();
exceptionHandlerCatchType(eh) = s.read2();
}
set(t, code, CodeExceptionHandlerTable, eht);
}
unsigned attributeCount = s.read2();
for (unsigned j = 0; j < attributeCount; ++j) {
object name = singletonObject(t, pool, s.read2() - 1);
unsigned length = s.read4();
if (strcmp(reinterpret_cast<const int8_t*>("LineNumberTable"),
&byteArrayBody(t, name, 0)) == 0)
{
unsigned lntLength = s.read2();
object lnt = makeLineNumberTable(t, lntLength, false);
for (unsigned i = 0; i < lntLength; ++i) {
LineNumber* ln = lineNumberTableBody(t, lnt, i);
lineNumberIp(ln) = s.read2();
lineNumberLine(ln) = s.read2();
}
set(t, code, CodeLineNumberTable, lnt);
} else {
s.skip(length);
}
}
return code;
}
void
scanMethodSpec(Thread* t, const char* s, unsigned* parameterCount,
unsigned* returnCode)
{
unsigned count = 0;
MethodSpecIterator it(t, s);
for (; it.hasNext(); it.next()) {
++ count;
}
*parameterCount = count;
*returnCode = fieldCode(t, *it.returnSpec());
}
void
parseMethodTable(Thread* t, Stream& s, object class_, object pool)
{
PROTECT(t, class_);
PROTECT(t, pool);
object virtualMap = makeHashMap(t, 0, 0);
PROTECT(t, virtualMap);
unsigned virtualCount = 0;
unsigned declaredVirtualCount = 0;
object superVirtualTable = 0;
PROTECT(t, superVirtualTable);
if (classFlags(t, class_) & ACC_INTERFACE) {
object itable = classInterfaceTable(t, class_);
if (itable) {
2007-08-14 00:37:00 +00:00
PROTECT(t, itable);
for (unsigned i = 0; i < arrayLength(t, itable); ++i) {
object vtable = classVirtualTable(t, arrayBody(t, itable, i));
2007-08-14 00:37:00 +00:00
if (vtable) {
PROTECT(t, vtable);
for (unsigned j = 0; j < arrayLength(t, vtable); ++j) {
object method = arrayBody(t, vtable, j);
object n = hashMapFindNode
(t, virtualMap, method, methodHash, methodEqual);
if (n == 0) {
method = makeMethod
(t,
methodVmFlags(t, method),
methodReturnCode(t, method),
2007-08-14 00:37:00 +00:00
methodParameterCount(t, method),
methodParameterFootprint(t, method),
methodFlags(t, method),
virtualCount++,
methodName(t, method),
methodSpec(t, method),
class_,
2007-09-25 23:53:11 +00:00
0,
2007-08-14 00:37:00 +00:00
0);
hashMapInsert(t, virtualMap, method, method, methodHash);
}
}
}
}
}
} else {
if (classSuper(t, class_)) {
superVirtualTable = classVirtualTable(t, classSuper(t, class_));
}
if (superVirtualTable) {
virtualCount = arrayLength(t, superVirtualTable);
for (unsigned i = 0; i < virtualCount; ++i) {
object method = arrayBody(t, superVirtualTable, i);
hashMapInsert(t, virtualMap, method, method, methodHash);
}
}
}
object newVirtuals = makeList(t, 0, 0, 0);
PROTECT(t, newVirtuals);
unsigned count = s.read2();
if (count) {
object methodTable = makeArray(t, count, true);
PROTECT(t, methodTable);
for (unsigned i = 0; i < count; ++i) {
unsigned flags = s.read2();
unsigned name = s.read2();
unsigned spec = s.read2();
object code = 0;
unsigned attributeCount = s.read2();
for (unsigned j = 0; j < attributeCount; ++j) {
object name = singletonObject(t, pool, s.read2() - 1);
unsigned length = s.read4();
if (strcmp(reinterpret_cast<const int8_t*>("Code"),
&byteArrayBody(t, name, 0)) == 0)
{
code = parseCode(t, s, pool);
} else {
s.skip(length);
}
}
const char* specString = reinterpret_cast<const char*>
(&byteArrayBody(t, singletonObject(t, pool, spec - 1), 0));
unsigned parameterCount;
unsigned returnCode;
scanMethodSpec(t, specString, &parameterCount, &returnCode);
object method = t->m->processor->makeMethod
(t,
0, // vm flags
returnCode,
parameterCount,
parameterFootprint(t, specString, flags & ACC_STATIC),
flags,
0, // offset
singletonObject(t, pool, name - 1),
singletonObject(t, pool, spec - 1),
class_,
code);
PROTECT(t, method);
2007-11-05 14:28:46 +00:00
if (methodVirtual(t, method)) {
++ declaredVirtualCount;
object p = hashMapFindNode
(t, virtualMap, method, methodHash, methodEqual);
if (p) {
methodOffset(t, method) = methodOffset(t, tripleFirst(t, p));
set(t, p, TripleSecond, method);
} else {
methodOffset(t, method) = virtualCount++;
listAppend(t, newVirtuals, method);
hashMapInsert(t, virtualMap, method, method, methodHash);
}
2007-11-05 14:28:46 +00:00
} else {
methodOffset(t, method) = i;
if (strcmp(reinterpret_cast<const int8_t*>("<clinit>"),
&byteArrayBody(t, methodName(t, method), 0)) == 0)
{
methodVmFlags(t, method) |= ClassInitFlag;
classVmFlags(t, class_) |= NeedInitFlag;
}
}
set(t, methodTable, ArrayBody + (i * BytesPerWord), method);
}
set(t, class_, ClassMethodTable, methodTable);
}
bool populateInterfaceVtables = false;
2007-08-14 13:27:10 +00:00
if (declaredVirtualCount == 0
and (classFlags(t, class_) & ACC_INTERFACE) == 0)
{
if (classSuper(t, class_)) {
// inherit virtual table from superclass
set(t, class_, ClassVirtualTable, superVirtualTable);
if (classInterfaceTable(t, classSuper(t, class_))
and arrayLength(t, classInterfaceTable(t, class_))
== arrayLength(t, classInterfaceTable(t, classSuper(t, class_))))
{
// inherit interface table from superclass
set(t, class_, ClassInterfaceTable,
classInterfaceTable(t, classSuper(t, class_)));
} else {
populateInterfaceVtables = true;
}
} else {
// apparently, Object does not have any virtual methods. We
// give it a vtable anyway so code doesn't break elsewhere.
object vtable = makeArray(t, 0, false);
set(t, class_, ClassVirtualTable, vtable);
2007-11-27 22:23:00 +00:00
}
} else if (virtualCount) {
// generate class vtable
2007-07-17 13:22:29 +00:00
object vtable = makeArray(t, virtualCount, true);
2007-08-14 00:37:00 +00:00
unsigned i = 0;
if (classFlags(t, class_) & ACC_INTERFACE) {
PROTECT(t, vtable);
2007-08-14 00:37:00 +00:00
for (object it = hashMapIterator(t, virtualMap); it;
it = hashMapIteratorNext(t, it))
{
object method = tripleFirst(t, hashMapIteratorNode(t, it));
2007-08-14 00:37:00 +00:00
assert(t, arrayBody(t, vtable, methodOffset(t, method)) == 0);
set(t, vtable, ArrayBody + (methodOffset(t, method) * BytesPerWord),
method);
2007-08-14 00:37:00 +00:00
++ i;
}
} else {
if (superVirtualTable) {
for (; i < arrayLength(t, superVirtualTable); ++i) {
object method = arrayBody(t, superVirtualTable, i);
method = hashMapFind(t, virtualMap, method, methodHash, methodEqual);
set(t, vtable, ArrayBody + (i * BytesPerWord), method);
}
}
for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) {
set(t, vtable, ArrayBody + (i * BytesPerWord), pairFirst(t, p));
++ i;
}
}
2007-08-14 00:37:00 +00:00
assert(t, arrayLength(t, vtable) == i);
set(t, class_, ClassVirtualTable, vtable);
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
populateInterfaceVtables = true;
}
}
if (populateInterfaceVtables) {
// generate interface vtables
object itable = classInterfaceTable(t, class_);
if (itable) {
PROTECT(t, itable);
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
object ivtable = classVirtualTable(t, arrayBody(t, itable, i));
if (ivtable) {
object vtable = arrayBody(t, itable, i + 1);
for (unsigned j = 0; j < arrayLength(t, ivtable); ++j) {
object method = arrayBody(t, ivtable, j);
method = hashMapFind
(t, virtualMap, method, methodHash, methodEqual);
// note that method may be null in the case of an abstract
// class
2007-08-14 00:37:00 +00:00
set(t, vtable, ArrayBody + (j * BytesPerWord), method);
}
}
}
}
}
}
void
updateClassTables(Thread* t, object newClass, object oldClass)
{
object fieldTable = classFieldTable(t, newClass);
if (fieldTable) {
for (unsigned i = 0; i < arrayLength(t, fieldTable); ++i) {
set(t, arrayBody(t, fieldTable, i), FieldClass, newClass);
}
}
if (classFlags(t, newClass) & ACC_INTERFACE) {
object virtualTable = classVirtualTable(t, newClass);
if (virtualTable) {
for (unsigned i = 0; i < arrayLength(t, virtualTable); ++i) {
if (methodClass(t, arrayBody(t, virtualTable, i)) == oldClass) {
set(t, arrayBody(t, virtualTable, i), MethodClass, newClass);
}
}
}
} else {
object methodTable = classMethodTable(t, newClass);
if (methodTable) {
for (unsigned i = 0; i < arrayLength(t, methodTable); ++i) {
set(t, arrayBody(t, methodTable, i), MethodClass, newClass);
}
}
}
}
void
updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
{
expect(t, bootstrapClass != class_);
// verify that the classes have the same layout
expect(t, classSuper(t, bootstrapClass) == classSuper(t, class_));
expect(t, bootstrapClass == arrayBody(t, t->m->types, Machine::ClassType)
or classFixedSize(t, bootstrapClass) == classFixedSize(t, class_));
expect(t,
(classVmFlags(t, bootstrapClass) & ReferenceFlag)
or (classObjectMask(t, bootstrapClass) == 0
and classObjectMask(t, class_) == 0)
or intArrayEqual(t, classObjectMask(t, bootstrapClass),
classObjectMask(t, class_)));
PROTECT(t, bootstrapClass);
PROTECT(t, class_);
ENTER(t, Thread::ExclusiveState);
classVmFlags(t, bootstrapClass) &= ~BootstrapFlag;
classVmFlags(t, bootstrapClass) |= classVmFlags(t, class_);
classFlags(t, bootstrapClass) = classFlags(t, class_);
set(t, bootstrapClass, ClassSuper, classSuper(t, class_));
set(t, bootstrapClass, ClassInterfaceTable, classInterfaceTable(t, class_));
set(t, bootstrapClass, ClassVirtualTable, classVirtualTable(t, class_));
set(t, bootstrapClass, ClassFieldTable, classFieldTable(t, class_));
set(t, bootstrapClass, ClassMethodTable, classMethodTable(t, class_));
set(t, bootstrapClass, ClassStaticTable, classStaticTable(t, class_));
updateClassTables(t, bootstrapClass, class_);
}
object
makeArrayClass(Thread* t, unsigned dimensions, object spec,
object elementClass)
{
2007-08-20 02:57:32 +00:00
// todo: arrays should implement Cloneable and Serializable
object vtable = classVirtualTable
(t, arrayBody(t, t->m->types, Machine::JobjectType));
2007-12-11 21:26:59 +00:00
object c = t->m->processor->makeClass
(t,
0,
0,
dimensions,
2 * BytesPerWord,
BytesPerWord,
classObjectMask(t, arrayBody(t, t->m->types, Machine::ArrayType)),
spec,
arrayBody(t, t->m->types, Machine::JobjectType),
0,
vtable,
0,
2007-07-30 23:19:05 +00:00
0,
2007-08-20 02:57:32 +00:00
elementClass,
t->m->loader,
arrayLength(t, vtable));
2007-12-11 21:26:59 +00:00
t->m->processor->initVtable(t, c);
return c;
}
object
makeArrayClass(Thread* t, object spec)
{
PROTECT(t, spec);
const char* s = reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0));
const char* start = s;
unsigned dimensions = 0;
for (; *s == '['; ++s) ++ dimensions;
object elementSpec;
switch (*s) {
case 'L': {
++ s;
const char* elementSpecStart = s;
while (*s and *s != ';') ++ s;
elementSpec = makeByteArray(t, s - elementSpecStart + 1, false);
memcpy(&byteArrayBody(t, elementSpec, 0),
&byteArrayBody(t, spec, elementSpecStart - start),
s - elementSpecStart);
byteArrayBody(t, elementSpec, s - elementSpecStart) = 0;
} break;
default:
if (dimensions > 1) {
char c = *s;
elementSpec = makeByteArray(t, 3, false);
byteArrayBody(t, elementSpec, 0) = '[';
byteArrayBody(t, elementSpec, 1) = c;
byteArrayBody(t, elementSpec, 2) = 0;
-- dimensions;
} else {
abort(t);
}
}
object elementClass = hashMapFind
(t, t->m->bootstrapClassMap, elementSpec, byteArrayHash, byteArrayEqual);
if (elementClass == 0) {
elementClass = resolveClass(t, elementSpec);
if (UNLIKELY(t->exception)) return 0;
}
return makeArrayClass(t, dimensions, spec, elementClass);
}
void
removeMonitor(Thread* t, object o)
{
unsigned hash;
if (DebugMonitors) {
hash = objectHash(t, o);
}
object p = hashMapRemove(t, t->m->monitorMap, o, objectHash, objectEqual);
assert(t, p);
if (DebugMonitors) {
fprintf(stderr, "dispose monitor %p for object %x\n",
static_cast<System::Monitor*>(pointerValue(t, p)),
hash);
}
static_cast<System::Monitor*>(pointerValue(t, p))->dispose();
}
2007-07-29 00:02:32 +00:00
void
removeString(Thread* t, object o)
{
hashMapRemove(t, t->m->stringMap, o, stringHash, objectEqual);
}
void
bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask,
unsigned fixedSize, unsigned arrayElementSize, unsigned vtableLength)
{
2007-11-06 15:29:05 +00:00
object super = (superType >= 0 ? arrayBody(t, t->m->types, superType) : 0);
object mask;
if (objectMask) {
2007-11-06 15:29:05 +00:00
if (super
and classObjectMask(t, super)
and intArrayBody(t, classObjectMask(t, super), 0)
== static_cast<int32_t>(objectMask))
{
mask = classObjectMask(t, arrayBody(t, t->m->types, superType));
} else {
mask = makeIntArray(t, 1, false);
intArrayBody(t, mask, 0) = objectMask;
}
} else {
mask = 0;
}
2007-11-06 15:29:05 +00:00
super = (superType >= 0 ? arrayBody(t, t->m->types, superType) : 0);
object class_ = t->m->processor->makeClass
2007-11-05 14:28:46 +00:00
(t, 0, BootstrapFlag, 0, fixedSize, arrayElementSize, mask, 0, super, 0, 0,
0, 0, 0, t->m->loader, vtableLength);
set(t, t->m->types, ArrayBody + (type * BytesPerWord), class_);
}
void
2007-11-05 14:28:46 +00:00
bootJavaClass(Thread* t, Machine::Type type, int superType, const char* name,
int vtableLength, object bootMethod)
{
PROTECT(t, bootMethod);
object n = makeByteArray(t, name);
object class_ = arrayBody(t, t->m->types, type);
set(t, class_, ClassName, n);
2007-11-05 14:28:46 +00:00
object vtable;
if (vtableLength >= 0) {
PROTECT(t, class_);
vtable = makeArray(t, vtableLength, false);
for (int i = 0; i < vtableLength; ++ i) {
arrayBody(t, vtable, i) = bootMethod;
}
} else {
vtable = classVirtualTable(t, arrayBody(t, t->m->types, superType));
}
set(t, class_, ClassVirtualTable, vtable);
2007-12-11 21:26:59 +00:00
t->m->processor->initVtable(t, class_);
hashMapInsert(t, t->m->bootstrapClassMap, n, class_, byteArrayHash);
}
class HeapClient: public Heap::Client {
public:
HeapClient(Machine* m): m(m) { }
virtual void visitRoots(Heap::Visitor* v) {
v->visit(&(m->loader));
v->visit(&(m->bootstrapClassMap));
v->visit(&(m->monitorMap));
v->visit(&(m->stringMap));
v->visit(&(m->types));
v->visit(&(m->jniInterfaceTable));
for (Reference* r = m->jniReferences; r; r = r->next) {
v->visit(&(r->target));
}
for (Thread* t = m->rootThread; t; t = t->peer) {
::visitRoots(t, v);
}
postVisit(m->rootThread, v);
}
virtual void collect(void* context, Heap::CollectionType type) {
Thread* t = static_cast<Thread*>(context);
ENTER(t, Thread::ExclusiveState);
collect(t, type);
}
virtual bool isFixed(void* p) {
return objectFixed(m->rootThread, static_cast<object>(p));
}
virtual unsigned sizeInWords(void* p) {
Thread* t = m->rootThread;
object o = static_cast<object>(m->heap->follow(mask(p)));
unsigned n = baseSize(t, o, static_cast<object>
(m->heap->follow(objectClass(t, o))));
if (objectExtended(t, o)) {
++ n;
}
return n;
}
virtual unsigned copiedSizeInWords(void* p) {
Thread* t = m->rootThread;
object o = static_cast<object>(m->heap->follow(mask(p)));
assert(t, not objectFixed(t, o));
unsigned n = baseSize(t, o, static_cast<object>
(m->heap->follow(objectClass(t, o))));
if (objectExtended(t, o) or hashTaken(t, o)) {
++ n;
}
return n;
}
virtual void copy(void* srcp, void* dstp) {
Thread* t = m->rootThread;
object src = static_cast<object>(m->heap->follow(mask(srcp)));
assert(t, not objectFixed(t, src));
object class_ = static_cast<object>
(m->heap->follow(objectClass(t, src)));
unsigned base = baseSize(t, src, class_);
unsigned n = extendedSize(t, src, base);
object dst = static_cast<object>(dstp);
memcpy(dst, src, n * BytesPerWord);
if (hashTaken(t, src)) {
cast<uintptr_t>(dst, 0) &= PointerMask;
cast<uintptr_t>(dst, 0) |= ExtendedMark;
extendedWord(t, dst, base) = takeHash(t, src);
}
}
virtual void walk(void* p, Heap::Walker* w) {
object o = static_cast<object>(m->heap->follow(mask(p)));
2007-11-02 14:15:06 +00:00
::walk(m->rootThread, w, o);
}
void dispose() {
2008-04-13 18:15:04 +00:00
m->heap->free(this, sizeof(*this));
}
private:
Machine* m;
};
2007-07-06 23:50:26 +00:00
} // namespace
namespace vm {
Machine::Machine(System* system, Heap* heap, Finder* finder,
Processor* processor, const char* bootLibrary,
const char* builtins):
vtable(&javaVMVTable),
2007-07-06 23:50:26 +00:00
system(system),
2008-04-13 18:15:04 +00:00
heapClient(new (heap->allocate(sizeof(HeapClient)))
HeapClient(this)),
heap(heap),
finder(finder),
processor(processor),
2007-07-06 23:50:26 +00:00
rootThread(0),
exclusive(0),
2007-09-07 23:20:21 +00:00
jniReferences(0),
builtins(builtins),
2007-07-06 23:50:26 +00:00
activeCount(0),
liveCount(0),
fixedFootprint(0),
localThread(0),
2007-07-06 23:50:26 +00:00
stateLock(0),
heapLock(0),
classLock(0),
referenceLock(0),
libraries(0),
2007-07-30 23:19:05 +00:00
loader(0),
2007-07-06 23:50:26 +00:00
bootstrapClassMap(0),
monitorMap(0),
2007-07-29 00:02:32 +00:00
stringMap(0),
2007-07-06 23:50:26 +00:00
types(0),
2007-09-07 23:20:21 +00:00
jniInterfaceTable(0),
2007-07-06 23:50:26 +00:00
finalizers(0),
tenuredFinalizers(0),
finalizeQueue(0),
weakReferences(0),
tenuredWeakReferences(0),
unsafe(false),
heapPoolIndex(0)
2007-07-06 23:50:26 +00:00
{
heap->setClient(heapClient);
populateJNITables(&javaVMVTable, &jniEnvVTable);
2007-07-06 23:50:26 +00:00
if (not system->success(system->make(&localThread)) or
not system->success(system->make(&stateLock)) or
2007-07-06 23:50:26 +00:00
not system->success(system->make(&heapLock)) or
not system->success(system->make(&classLock)) or
not system->success(system->make(&referenceLock)) or
not system->success(system->load(&libraries, bootLibrary, false)))
2007-07-06 23:50:26 +00:00
{
system->abort();
}
}
void
Machine::dispose()
{
localThread->dispose();
2007-07-06 23:50:26 +00:00
stateLock->dispose();
heapLock->dispose();
classLock->dispose();
referenceLock->dispose();
2007-07-06 23:50:26 +00:00
if (libraries) {
libraries->disposeAll();
2007-07-06 23:50:26 +00:00
}
2007-09-07 23:20:21 +00:00
for (Reference* r = jniReferences; r;) {
Reference* tmp = r;
2007-09-07 23:20:21 +00:00
r = r->next;
2008-04-13 18:15:04 +00:00
heap->free(tmp, sizeof(*tmp));
2007-09-07 23:20:21 +00:00
}
2007-10-28 01:54:30 +00:00
for (unsigned i = 0; i < heapPoolIndex; ++i) {
2008-04-13 18:15:04 +00:00
heap->free(heapPool[i], Thread::HeapSizeInBytes);
2007-10-28 01:54:30 +00:00
}
static_cast<HeapClient*>(heapClient)->dispose();
2008-04-13 18:15:04 +00:00
heap->free(this, sizeof(*this));
2007-07-06 23:50:26 +00:00
}
2007-07-24 01:44:20 +00:00
Thread::Thread(Machine* m, object javaThread, Thread* parent):
2007-07-06 23:50:26 +00:00
vtable(&(m->jniEnvVTable)),
m(m),
2007-07-07 18:09:16 +00:00
parent(parent),
peer((parent ? parent->child : 0)),
2007-07-06 23:50:26 +00:00
child(0),
state(NoState),
2007-09-07 23:20:21 +00:00
criticalLevel(0),
2007-07-07 18:09:16 +00:00
systemThread(0),
javaThread(javaThread),
2007-07-06 23:50:26 +00:00
exception(0),
heapIndex(0),
heapOffset(0),
2007-07-28 21:28:25 +00:00
protector(0),
runnable(this),
defaultHeap(static_cast<uintptr_t*>
2008-04-13 18:15:04 +00:00
(m->heap->allocate(HeapSizeInBytes))),
2008-04-09 19:08:13 +00:00
heap(defaultHeap),
backupHeap(0),
backupHeapIndex(0),
backupHeapSizeInWords(0),
tracing(false)
#ifdef VM_STRESS
, stress(false)
#endif // VM_STRESS
{ }
void
Thread::init()
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-28 21:28:25 +00:00
if (not m->system->success(m->system->attach(&runnable))) {
2007-07-07 18:09:16 +00:00
abort(this);
}
2007-07-06 23:50:26 +00:00
Thread* t = this;
2007-10-28 01:54:30 +00:00
t->m->loader = allocate(t, sizeof(void*) * 3, true);
memset(t->m->loader, 0, sizeof(void*) * 2);
2007-07-30 23:19:05 +00:00
t->m->types = allocate(t, pad((TypeCount + 2) * BytesPerWord), true);
arrayLength(t, t->m->types) = TypeCount;
memset(&arrayBody(t, t->m->types, 0), 0, TypeCount * BytesPerWord);
2007-07-06 23:50:26 +00:00
#include "type-initializations.cpp"
object arrayClass = arrayBody(t, t->m->types, Machine::ArrayType);
set(t, t->m->types, 0, arrayClass);
2007-07-06 23:50:26 +00:00
2007-07-30 23:19:05 +00:00
object loaderClass = arrayBody
(t, t->m->types, Machine::SystemClassLoaderType);
set(t, t->m->loader, 0, loaderClass);
2007-07-30 23:19:05 +00:00
object objectClass = arrayBody(t, m->types, Machine::JobjectType);
2007-07-06 23:50:26 +00:00
object classClass = arrayBody(t, m->types, Machine::ClassType);
set(t, classClass, 0, classClass);
set(t, classClass, ClassSuper, objectClass);
2007-07-06 23:50:26 +00:00
object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType);
set(t, intArrayClass, 0, classClass);
set(t, intArrayClass, ClassSuper, objectClass);
2007-07-06 23:50:26 +00:00
m->unsafe = false;
2007-11-02 21:08:14 +00:00
classVmFlags(t, arrayBody(t, m->types, Machine::SingletonType))
|= SingletonFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JreferenceType))
|= ReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType))
|= ReferenceFlag | WeakReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::PhantomReferenceType))
|= ReferenceFlag | WeakReferenceFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JbooleanType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JbyteType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JcharType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JshortType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JintType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JlongType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JfloatType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JdoubleType))
|= PrimitiveFlag;
classVmFlags(t, arrayBody(t, m->types, Machine::JvoidType))
|= PrimitiveFlag;
m->bootstrapClassMap = makeHashMap(this, 0, 0);
2007-07-06 23:50:26 +00:00
{ object loaderMap = makeHashMap(this, 0, 0);
set(t, m->loader, SystemClassLoaderMap, loaderMap);
}
2007-07-30 23:19:05 +00:00
m->monitorMap = makeWeakHashMap(this, 0, 0);
m->stringMap = makeWeakHashMap(this, 0, 0);
2007-07-06 23:50:26 +00:00
2007-09-07 23:20:21 +00:00
m->jniInterfaceTable = makeVector(this, 0, 0, false);
m->localThread->set(this);
2007-09-30 02:48:27 +00:00
{ object bootCode = makeCode(t, 0, 0, 0, 0, 0, 1, false);
codeBody(t, bootCode, 0) = impdep1;
object bootMethod = makeMethod
(t, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode, 0);
PROTECT(t, bootMethod);
2007-09-30 02:48:27 +00:00
#include "type-java-initializations.cpp"
}
2007-07-07 18:09:16 +00:00
} else {
2007-11-27 22:23:00 +00:00
peer = parent->child;
2007-07-07 18:09:16 +00:00
parent->child = this;
}
if (javaThread) {
threadPeer(this, javaThread) = reinterpret_cast<jlong>(this);
} else {
this->javaThread = makeThread
(this, reinterpret_cast<int64_t>(this), 0, 0, 0, 0, m->loader);
}
2007-07-07 18:09:16 +00:00
}
void
Thread::exit()
{
if (state != Thread::ExitState and
state != Thread::ZombieState)
{
enter(this, Thread::ExclusiveState);
if (m->liveCount == 1) {
2007-07-07 18:09:16 +00:00
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 (systemThread) {
systemThread->dispose();
}
2008-04-13 18:15:04 +00:00
m->heap->free(defaultHeap, Thread::HeapSizeInBytes);
2007-07-17 00:23:23 +00:00
m->processor->dispose(this);
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->m->rootThread);
2007-07-07 18:09:16 +00:00
for (object* p = &(t->m->finalizers); *p;) {
2007-07-17 01:55:49 +00:00
object f = *p;
*p = finalizerNext(t, *p);
void (*function)(Thread*, object);
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
function(t, finalizerTarget(t, f));
2007-07-07 18:09:16 +00:00
}
for (object* p = &(t->m->tenuredFinalizers); *p;) {
2007-07-17 01:55:49 +00:00
object f = *p;
*p = finalizerNext(t, *p);
void (*function)(Thread*, object);
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
function(t, finalizerTarget(t, f));
2007-07-11 04:19:26 +00:00
}
disposeAll(t, t->m->rootThread);
2007-07-07 18:09:16 +00:00
}
2007-07-06 23:50:26 +00:00
void
enter(Thread* t, Thread::State s)
{
stress(t);
2007-07-06 23:50:26 +00:00
if (s == t->state) return;
2007-07-18 01:33:00 +00:00
if (t->state == Thread::ExitState) {
// once in exit state, we stay that way
return;
}
ACQUIRE_RAW(t, t->m->stateLock);
2007-07-06 23:50:26 +00:00
switch (s) {
case Thread::ExclusiveState: {
while (t->m->exclusive) {
2007-07-06 23:50:26 +00:00
// 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
}
switch (t->state) {
case Thread::ActiveState: break;
case Thread::IdleState: {
++ t->m->activeCount;
} break;
default: abort(t);
}
2007-07-06 23:50:26 +00:00
t->state = Thread::ExclusiveState;
t->m->exclusive = t;
2007-07-06 23:50:26 +00:00
while (t->m->activeCount > 1) {
t->m->stateLock->wait(t->systemThread, 0);
2007-07-06 23:50:26 +00:00
}
} break;
case Thread::IdleState:
case Thread::ZombieState: {
switch (t->state) {
case Thread::ExclusiveState: {
assert(t, t->m->exclusive == t);
t->m->exclusive = 0;
2007-07-06 23:50:26 +00:00
} break;
case Thread::ActiveState: break;
default: abort(t);
}
assert(t, t->m->activeCount > 0);
-- t->m->activeCount;
2007-07-18 01:33:00 +00:00
2007-07-06 23:50:26 +00:00
if (s == Thread::ZombieState) {
assert(t, t->m->liveCount > 0);
-- t->m->liveCount;
2007-07-06 23:50:26 +00:00
}
t->state = s;
t->m->stateLock->notifyAll(t->systemThread);
2007-07-06 23:50:26 +00:00
} break;
case Thread::ActiveState: {
switch (t->state) {
case Thread::ExclusiveState: {
assert(t, t->m->exclusive == t);
2007-07-06 23:50:26 +00:00
t->state = s;
t->m->exclusive = 0;
2007-07-06 23:50:26 +00:00
t->m->stateLock->notifyAll(t->systemThread);
2007-07-06 23:50:26 +00:00
} break;
case Thread::NoState:
case Thread::IdleState: {
while (t->m->exclusive) {
t->m->stateLock->wait(t->systemThread, 0);
2007-07-06 23:50:26 +00:00
}
++ t->m->activeCount;
2007-07-06 23:50:26 +00:00
if (t->state == Thread::NoState) {
++ t->m->liveCount;
2007-07-06 23:50:26 +00:00
}
t->state = s;
} break;
default: abort(t);
}
} break;
case Thread::ExitState: {
switch (t->state) {
case Thread::ExclusiveState: {
assert(t, t->m->exclusive == t);
t->m->exclusive = 0;
2007-11-27 22:23:00 +00:00
t->m->stateLock->notifyAll(t->systemThread);
2007-07-06 23:50:26 +00:00
} break;
case Thread::ActiveState: break;
default: abort(t);
}
2007-07-18 01:33:00 +00:00
assert(t, t->m->activeCount > 0);
-- t->m->activeCount;
2007-07-18 01:33:00 +00:00
2007-07-06 23:50:26 +00:00
t->state = s;
while (t->m->liveCount > 1) {
t->m->stateLock->wait(t->systemThread, 0);
2007-07-06 23:50:26 +00:00
}
} break;
default: abort(t);
}
}
object
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask)
{
return allocate3
(t, t->m->heap,
ceiling(sizeInBytes, BytesPerWord) > Thread::HeapSizeInWords ?
Machine::FixedAllocation : Machine::MovableAllocation,
2008-04-13 18:15:04 +00:00
sizeInBytes, objectMask);
}
object
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
2008-04-13 18:15:04 +00:00
unsigned sizeInBytes, bool objectMask)
2007-10-28 01:54:30 +00:00
{
2008-04-09 19:08:13 +00:00
if (t->backupHeap) {
expect(t, t->backupHeapIndex + ceiling(sizeInBytes, BytesPerWord)
<= t->backupHeapSizeInWords);
object o = reinterpret_cast<object>(t->backupHeap + t->backupHeapIndex);
t->backupHeapIndex += ceiling(sizeInBytes, BytesPerWord);
cast<object>(o, 0) = 0;
return o;
} else if (t->tracing) {
expect(t, t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
<= Thread::HeapSizeInWords);
return allocateSmall(t, sizeInBytes);
2008-04-09 19:08:13 +00:00
}
ACQUIRE_RAW(t, t->m->stateLock);
2007-07-06 23:50:26 +00:00
while (t->m->exclusive and t->m->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 (type == Machine::FixedAllocation) {
if (t->m->fixedFootprint + sizeInBytes
> Machine::FixedFootprintThresholdInBytes)
{
t->heap = 0;
}
} else if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
2008-04-09 19:08:13 +00:00
> Thread::HeapSizeInWords)
2007-07-06 23:50:26 +00:00
{
t->heap = 0;
if (t->m->heapPoolIndex < Machine::HeapPoolSize) {
t->heap = static_cast<uintptr_t*>
2008-04-13 18:15:04 +00:00
(t->m->heap->tryAllocate(Thread::HeapSizeInBytes));
if (t->heap) {
t->m->heapPool[t->m->heapPoolIndex++] = t->heap;
t->heapOffset += t->heapIndex;
t->heapIndex = 0;
}
}
}
if (t->heap == 0) {
ENTER(t, Thread::ExclusiveState);
// fprintf(stderr, "gc");
// vmPrintTrace(t);
collect(t, Heap::MinorCollection);
2007-07-06 23:50:26 +00:00
}
switch (type) {
case Machine::MovableAllocation: {
return allocateSmall(t, sizeInBytes);
}
2007-07-06 23:50:26 +00:00
case Machine::FixedAllocation: {
unsigned total;
object o = static_cast<object>
(t->m->heap->allocateFixed
(allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total));
cast<uintptr_t>(o, 0) = FixedMark;
t->m->fixedFootprint += total;
return o;
}
case Machine::ImmortalAllocation: {
unsigned total;
object o = static_cast<object>
(t->m->heap->allocateImmortal
2008-04-13 18:15:04 +00:00
(allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total));
cast<uintptr_t>(o, 0) = FixedMark;
return o;
}
default: abort(t);
2007-07-06 23:50:26 +00:00
}
}
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);
2007-07-11 01:38:06 +00:00
return makeString(t, s, 0, byteArrayLength(t, s) - 1, 0);
2007-07-06 23:50:26 +00:00
}
void
stringChars(Thread* t, object string, char* chars)
{
object data = stringData(t, string);
if (objectClass(t, data)
== arrayBody(t, t->m->types, Machine::ByteArrayType))
{
memcpy(chars,
&byteArrayBody(t, data, stringOffset(t, string)),
stringLength(t, string));
} else {
for (unsigned i = 0; i < stringLength(t, string); ++i) {
chars[i] = charArrayBody(t, data, stringOffset(t, string) + i);
}
}
chars[stringLength(t, string)] = 0;
}
void
2008-04-02 12:57:25 +00:00
stringChars(Thread* t, object string, uint16_t* chars)
{
object data = stringData(t, string);
if (objectClass(t, data)
== arrayBody(t, t->m->types, Machine::ByteArrayType))
{
for (unsigned i = 0; i < stringLength(t, string); ++i) {
chars[i] = byteArrayBody(t, data, stringOffset(t, string) + i);
}
} else {
memcpy(chars,
&charArrayBody(t, data, stringOffset(t, string)),
2008-04-02 12:57:25 +00:00
stringLength(t, string) * sizeof(uint16_t));
}
chars[stringLength(t, string)] = 0;
}
2007-07-24 01:44:20 +00:00
bool
isAssignableFrom(Thread* t, object a, object b)
{
2007-11-05 14:28:46 +00:00
if (a == b) return true;
if (classFlags(t, a) & ACC_INTERFACE) {
2007-11-04 23:10:33 +00:00
if (classVmFlags(t, b) & BootstrapFlag) {
resolveClass(t, className(t, b));
if (UNLIKELY(t->exception)) {
t->exception = 0;
return false;
}
2007-11-04 23:10:33 +00:00
}
2007-08-20 02:57:32 +00:00
2007-07-24 01:44:20 +00:00
for (; b; b = classSuper(t, b)) {
object itable = classInterfaceTable(t, b);
if (itable) {
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
if (arrayBody(t, itable, i) == a) {
return true;
}
2007-07-24 01:44:20 +00:00
}
}
}
2007-08-20 02:57:32 +00:00
} else if (classArrayDimensions(t, a)) {
if (classArrayDimensions(t, b)) {
return isAssignableFrom
(t, classStaticTable(t, a), classStaticTable(t, b));
}
2007-07-24 01:44:20 +00:00
} else {
for (; b; b = classSuper(t, b)) {
if (b == a) {
return true;
}
}
}
return false;
}
bool
instanceOf(Thread* t, object class_, object o)
{
if (o == 0) {
return false;
2007-07-24 03:16:59 +00:00
} else {
return isAssignableFrom(t, class_, objectClass(t, o));
2007-07-24 01:44:20 +00:00
}
}
2007-07-28 16:10:13 +00:00
object
classInitializer(Thread* t, object class_)
{
for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, class_)); ++i) {
object o = arrayBody(t, classMethodTable(t, class_), i);
if (strcmp(reinterpret_cast<const int8_t*>("<clinit>"),
&byteArrayBody(t, methodName(t, o), 0)) == 0)
{
return o;
}
}
abort(t);
}
unsigned
fieldCode(Thread* t, unsigned javaCode)
2007-07-06 23:50:26 +00:00
{
switch (javaCode) {
case 'B':
return ByteField;
case 'C':
return CharField;
case 'D':
return DoubleField;
case 'F':
return FloatField;
case 'I':
return IntField;
case 'J':
return LongField;
case 'S':
return ShortField;
case 'V':
return VoidField;
case 'Z':
return BooleanField;
case 'L':
case '[':
return ObjectField;
2007-07-06 23:50:26 +00:00
default: abort(t);
}
}
2007-07-06 23:50:26 +00:00
unsigned
fieldType(Thread* t, unsigned code)
{
switch (code) {
case VoidField:
return VOID_TYPE;
case ByteField:
case BooleanField:
return INT8_TYPE;
case CharField:
case ShortField:
return INT16_TYPE;
case DoubleField:
return DOUBLE_TYPE;
case FloatField:
return FLOAT_TYPE;
case IntField:
return INT32_TYPE;
case LongField:
return INT64_TYPE;
case ObjectField:
return POINTER_TYPE;
default: abort(t);
}
2007-07-06 23:50:26 +00:00
}
unsigned
primitiveSize(Thread* t, unsigned code)
2007-07-11 04:19:26 +00:00
{
switch (code) {
case VoidField:
return 0;
case ByteField:
case BooleanField:
return 1;
case CharField:
case ShortField:
return 2;
case FloatField:
case IntField:
return 4;
case DoubleField:
case LongField:
return 8;
2007-07-11 04:19:26 +00:00
default: abort(t);
}
}
2007-07-11 04:19:26 +00:00
2007-07-30 23:19:05 +00:00
object
findLoadedClass(Thread* t, object spec)
2007-07-30 23:19:05 +00:00
{
PROTECT(t, spec);
ACQUIRE(t, t->m->classLock);
2007-07-30 23:19:05 +00:00
return hashMapFind(t, systemClassLoaderMap(t, t->m->loader),
2007-07-30 23:19:05 +00:00
spec, byteArrayHash, byteArrayEqual);
}
object
parseClass(Thread* t, const uint8_t* data, unsigned size)
{
class Client : public Stream::Client {
public:
Client(Thread* t): t(t) { }
virtual void NO_RETURN handleError() {
2007-07-30 23:19:05 +00:00
abort(t);
}
private:
Thread* t;
} client(t);
Stream s(&client, data, size);
uint32_t magic = s.read4();
expect(t, magic == 0xCAFEBABE);
2007-07-30 23:19:05 +00:00
s.read2(); // minor version
s.read2(); // major version
object pool = parsePool(t, s);
PROTECT(t, pool);
unsigned flags = s.read2();
unsigned name = s.read2();
object class_ = makeClass(t,
flags,
0, // VM flags
0, // array dimensions
0, // fixed size
0, // array size
0, // object mask
singletonObject(t, pool, name - 1),
2007-07-30 23:19:05 +00:00
0, // super
0, // interfaces
0, // vtable
0, // fields
0, // methods
0, // static table
t->m->loader,
0, // vtable length
false);
2007-07-30 23:19:05 +00:00
PROTECT(t, class_);
unsigned super = s.read2();
if (super) {
object sc = resolveClass(t, singletonObject(t, pool, super - 1));
2007-07-30 23:19:05 +00:00
if (UNLIKELY(t->exception)) return 0;
set(t, class_, ClassSuper, sc);
2007-07-30 23:19:05 +00:00
classVmFlags(t, class_)
|= (classVmFlags(t, sc) & (ReferenceFlag | WeakReferenceFlag));
}
parseInterfaceTable(t, s, class_, pool);
if (UNLIKELY(t->exception)) return 0;
parseFieldTable(t, s, class_, pool);
if (UNLIKELY(t->exception)) return 0;
parseMethodTable(t, s, class_, pool);
if (UNLIKELY(t->exception)) return 0;
object vtable = classVirtualTable(t, class_);
unsigned vtableLength = (vtable ? arrayLength(t, vtable) : 0);
object real = t->m->processor->makeClass
(t,
classFlags(t, class_),
classVmFlags(t, class_),
classArrayDimensions(t, class_),
classFixedSize(t, class_),
classArrayElementSize(t, class_),
classObjectMask(t, class_),
className(t, class_),
classSuper(t, class_),
classInterfaceTable(t, class_),
classVirtualTable(t, class_),
classFieldTable(t, class_),
classMethodTable(t, class_),
classStaticTable(t, class_),
classLoader(t, class_),
vtableLength);
2007-12-11 21:26:59 +00:00
t->m->processor->initVtable(t, real);
updateClassTables(t, real, class_);
return real;
2007-07-30 23:19:05 +00:00
}
object
resolveClass(Thread* t, object spec)
{
PROTECT(t, spec);
ACQUIRE(t, t->m->classLock);
object class_ = hashMapFind(t, systemClassLoaderMap(t, t->m->loader),
2007-07-30 23:19:05 +00:00
spec, byteArrayHash, byteArrayEqual);
if (class_ == 0) {
if (byteArrayBody(t, spec, 0) == '[') {
class_ = hashMapFind
(t, t->m->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual);
if (class_) {
set(t, class_, ClassVirtualTable,
classVirtualTable
(t, arrayBody(t, t->m->types, Machine::JobjectType)));
} else {
class_ = makeArrayClass(t, spec);
}
} else {
char file[byteArrayLength(t, spec) + 6];
memcpy(file, &byteArrayBody(t, spec, 0), byteArrayLength(t, spec) - 1);
memcpy(file + byteArrayLength(t, spec) - 1, ".class", 7);
System::Region* region = t->m->finder->find(file);
2007-09-17 00:13:36 +00:00
if (region) {
if (Verbose) {
fprintf(stderr, "parsing %s\n", &byteArrayBody(t, spec, 0));
}
// parse class file
2007-09-17 00:13:36 +00:00
class_ = parseClass(t, region->start(), region->length());
region->dispose();
if (LIKELY(t->exception == 0)) {
if (Verbose) {
fprintf(stderr, "done parsing %s: %p\n",
&byteArrayBody(t, spec, 0),
class_);
}
object bootstrapClass = hashMapFind
(t, t->m->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual);
if (bootstrapClass) {
PROTECT(t, bootstrapClass);
updateBootstrapClass(t, bootstrapClass, class_);
class_ = bootstrapClass;
}
}
}
}
if (class_) {
PROTECT(t, class_);
hashMapInsert(t, systemClassLoaderMap(t, t->m->loader),
2007-07-30 23:19:05 +00:00
spec, class_, byteArrayHash);
} else if (t->exception == 0) {
object message = makeString(t, "%s", &byteArrayBody(t, spec, 0));
t->exception = makeClassNotFoundException(t, message);
}
2007-07-11 04:19:26 +00:00
}
return class_;
}
object
resolveMethod(Thread* t, const char* className, const char* methodName,
const char* methodSpec)
{
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);
return findMethodInClass(t, class_, referenceName(t, reference),
referenceSpec(t, reference));
}
return 0;
}
object
resolveObjectArrayClass(Thread* t, object elementSpec)
{
PROTECT(t, elementSpec);
object spec;
if (byteArrayBody(t, elementSpec, 0) == '[') {
spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 1, false);
byteArrayBody(t, spec, 0) = '[';
memcpy(&byteArrayBody(t, spec, 1),
&byteArrayBody(t, elementSpec, 0),
byteArrayLength(t, elementSpec));
} else {
spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 3, false);
byteArrayBody(t, spec, 0) = '[';
byteArrayBody(t, spec, 1) = 'L';
memcpy(&byteArrayBody(t, spec, 2),
&byteArrayBody(t, elementSpec, 0),
byteArrayLength(t, elementSpec) - 1);
byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 1) = ';';
byteArrayBody(t, spec, byteArrayLength(t, elementSpec) + 2) = 0;
}
return resolveClass(t, spec);
}
object
makeObjectArray(Thread* t, object elementClass, unsigned count, bool clear)
{
object arrayClass = resolveObjectArrayClass(t, className(t, elementClass));
PROTECT(t, arrayClass);
object array = makeArray(t, count, clear);
setObjectClass(t, array, arrayClass);
return array;
}
object
findInTable(Thread* t, object table, object name, object spec,
object& (*getName)(Thread*, object),
object& (*getSpec)(Thread*, object))
{
if (table) {
for (unsigned i = 0; i < arrayLength(t, table); ++i) {
object o = arrayBody(t, table, i);
if (strcmp(&byteArrayBody(t, getName(t, o), 0),
&byteArrayBody(t, name, 0)) == 0 and
strcmp(&byteArrayBody(t, getSpec(t, o), 0),
&byteArrayBody(t, spec, 0)) == 0)
{
return o;
}
}
// fprintf(stderr, "%s %s not in\n",
// &byteArrayBody(t, name, 0),
// &byteArrayBody(t, spec, 0));
// for (unsigned i = 0; i < arrayLength(t, table); ++i) {
// object o = arrayBody(t, table, i);
// fprintf(stderr, "\t%s %s\n",
// &byteArrayBody(t, getName(t, o), 0),
// &byteArrayBody(t, getSpec(t, o), 0));
// }
}
return 0;
}
object
findInHierarchy(Thread* t, object class_, object name, object spec,
object (*find)(Thread*, object, object, object),
object (*makeError)(Thread*, object))
{
object originalClass = class_;
PROTECT(t, class_);
object o = 0;
if (classFlags(t, class_) & ACC_INTERFACE) {
if (classVirtualTable(t, class_)) {
o = findInTable
(t, classVirtualTable(t, class_), name, spec, methodName, methodSpec);
}
} else {
for (; o == 0 and class_; class_ = classSuper(t, class_)) {
o = find(t, class_, name, spec);
}
}
if (o == 0) {
object message = makeString
(t, "%s %s not found in %s",
&byteArrayBody(t, name, 0),
&byteArrayBody(t, spec, 0),
&byteArrayBody(t, className(t, originalClass), 0));
t->exception = makeError(t, message);
}
return o;
}
unsigned
parameterFootprint(Thread* t, const char* s, bool static_)
{
unsigned footprint = 0;
for (MethodSpecIterator it(t, s); it.hasNext();) {
switch (*it.next()) {
case 'J':
case 'D':
footprint += 2;
break;
default:
++ footprint;
break;
}
}
if (not static_) {
++ footprint;
}
return footprint;
}
void
addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object))
{
PROTECT(t, target);
ACQUIRE(t, t->m->referenceLock);
void* function;
memcpy(&function, &finalize, BytesPerWord);
object f = makeFinalizer(t, 0, function, 0);
2007-08-14 00:37:00 +00:00
finalizerTarget(t, f) = target;
finalizerNext(t, f) = t->m->finalizers;
t->m->finalizers = f;
2007-07-11 04:19:26 +00:00
}
2007-07-06 23:50:26 +00:00
System::Monitor*
2007-11-27 22:23:00 +00:00
objectMonitor(Thread* t, object o, bool createNew)
2007-07-06 23:50:26 +00:00
{
assert(t, t->state == Thread::ActiveState);
object p = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual);
2007-07-06 23:50:26 +00:00
if (p) {
if (DebugMonitors) {
2007-07-11 04:19:26 +00:00
fprintf(stderr, "found monitor %p for object %x\n",
static_cast<System::Monitor*>(pointerValue(t, p)),
objectHash(t, o));
}
2007-07-06 23:50:26 +00:00
return static_cast<System::Monitor*>(pointerValue(t, p));
2007-11-27 22:23:00 +00:00
} else if (createNew) {
2007-07-06 23:50:26 +00:00
PROTECT(t, o);
ENTER(t, Thread::ExclusiveState);
p = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual);
if (p) {
if (DebugMonitors) {
fprintf(stderr, "found monitor %p for object %x\n",
static_cast<System::Monitor*>(pointerValue(t, p)),
objectHash(t, o));
}
return static_cast<System::Monitor*>(pointerValue(t, p));
}
2007-07-06 23:50:26 +00:00
System::Monitor* m;
System::Status s = t->m->system->make(&m);
expect(t, t->m->system->success(s));
2007-07-06 23:50:26 +00:00
if (DebugMonitors) {
2007-07-11 04:19:26 +00:00
fprintf(stderr, "made monitor %p for object %x\n",
m,
objectHash(t, o));
}
2007-07-06 23:50:26 +00:00
p = makePointer(t, m);
hashMapInsert(t, t->m->monitorMap, o, p, objectHash);
2007-07-06 23:50:26 +00:00
addFinalizer(t, o, removeMonitor);
return m;
2007-11-27 22:23:00 +00:00
} else {
return 0;
2007-07-06 23:50:26 +00:00
}
}
2007-07-29 00:02:32 +00:00
object
intern(Thread* t, object s)
{
PROTECT(t, s);
ACQUIRE(t, t->m->referenceLock);
2007-07-29 00:02:32 +00:00
object n = hashMapFindNode(t, t->m->stringMap, s, stringHash, stringEqual);
2007-07-29 00:02:32 +00:00
if (n) {
return jreferenceTarget(t, tripleFirst(t, n));
} else {
hashMapInsert(t, t->m->stringMap, s, 0, stringHash);
2007-07-29 00:02:32 +00:00
addFinalizer(t, s, removeString);
return s;
}
}
void
collect(Thread* t, Heap::CollectionType type)
{
2007-12-16 22:41:07 +00:00
#ifdef VM_STRESS
bool stress = t->stress;
if (not stress) t->stress = true;
#endif
Machine* m = t->m;
m->unsafe = true;
m->heap->collect(type, footprint(m->rootThread));
m->unsafe = false;
postCollect(m->rootThread);
for (object f = m->finalizeQueue; f; f = finalizerNext(t, f)) {
void (*function)(Thread*, object);
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
function(t, finalizerTarget(t, f));
}
m->finalizeQueue = 0;
killZombies(t, m->rootThread);
for (unsigned i = 0; i < m->heapPoolIndex; ++i) {
2008-04-13 18:15:04 +00:00
m->heap->free(m->heapPool[i], Thread::HeapSizeInBytes);
}
m->heapPoolIndex = 0;
2007-10-28 01:54:30 +00:00
m->fixedFootprint = 0;
2007-12-16 22:41:07 +00:00
#ifdef VM_STRESS
if (not stress) t->stress = false;
#endif
}
2007-07-24 03:16:59 +00:00
void
printTrace(Thread* t, object exception)
{
if (exception == 0) {
2007-10-13 00:22:52 +00:00
exception = makeNullPointerException(t, 0, makeTrace(t), 0);
}
2007-10-13 00:22:52 +00:00
for (object e = exception; e; e = throwableCause(t, e)) {
2007-07-24 03:16:59 +00:00
if (e != exception) {
fprintf(stderr, "caused by: ");
}
fprintf(stderr, "%s", &byteArrayBody
(t, className(t, objectClass(t, e)), 0));
if (throwableMessage(t, e)) {
object m = throwableMessage(t, e);
2007-07-24 03:16:59 +00:00
char message[stringLength(t, m) + 1];
stringChars(t, m, message);
fprintf(stderr, ": %s\n", message);
} else {
fprintf(stderr, "\n");
}
object trace = throwableTrace(t, e);
2007-07-24 03:16:59 +00:00
for (unsigned i = 0; i < arrayLength(t, trace); ++i) {
object e = arrayBody(t, trace, i);
const int8_t* class_ = &byteArrayBody
(t, className(t, methodClass(t, traceElementMethod(t, e))), 0);
const int8_t* method = &byteArrayBody
(t, methodName(t, traceElementMethod(t, e)), 0);
2007-10-04 22:41:19 +00:00
int line = t->m->processor->lineNumber
(t, traceElementMethod(t, e), traceElementIp(t, e));
2007-07-24 03:16:59 +00:00
fprintf(stderr, " at %s.%s ", class_, method);
switch (line) {
case NativeLine:
fprintf(stderr, "(native)\n");
break;
case UnknownLine:
fprintf(stderr, "(unknown line)\n");
break;
default:
fprintf(stderr, "(line %d)\n", line);
}
}
}
}
object
makeTrace(Thread* t, Processor::StackWalker* walker)
{
class Visitor: public Processor::StackVisitor {
public:
Visitor(Thread* t): t(t), trace(0), index(0), protector(t, &trace) { }
2007-09-24 13:46:48 +00:00
virtual bool visit(Processor::StackWalker* walker) {
if (trace == 0) {
trace = makeArray(t, walker->count(), true);
}
object e = makeTraceElement(t, walker->method(), walker->ip());
2008-04-23 16:33:31 +00:00
assert(t, index < arrayLength(t, trace));
set(t, trace, ArrayBody + (index * BytesPerWord), e);
++ index;
return true;
}
Thread* t;
object trace;
unsigned index;
Thread::SingleProtector protector;
} v(t);
walker->walk(&v);
return v.trace ? v.trace : makeArray(t, 0, true);
}
object
2008-04-09 19:08:13 +00:00
makeTrace(Thread* t, Thread* target)
{
class Visitor: public Processor::StackVisitor {
public:
Visitor(Thread* t): t(t), trace(0) { }
virtual bool visit(Processor::StackWalker* walker) {
trace = makeTrace(t, walker);
return false;
}
Thread* t;
object trace;
} v(t);
2008-04-09 19:08:13 +00:00
t->m->processor->walkStack(target, &v);
return v.trace ? v.trace : makeArray(t, 0, true);
}
void
noop()
{ }
2007-07-06 23:50:26 +00:00
#include "type-constructors.cpp"
} // namespace vm
// for debugging
void
vmPrintTrace(Thread* t)
{
class Visitor: public Processor::StackVisitor {
public:
Visitor(Thread* t): t(t) { }
virtual bool visit(Processor::StackWalker* walker) {
const int8_t* class_ = &byteArrayBody
(t, className(t, methodClass(t, walker->method())), 0);
const int8_t* method = &byteArrayBody
(t, methodName(t, walker->method()), 0);
int line = t->m->processor->lineNumber
(t, walker->method(), walker->ip());
fprintf(stderr, " at %s.%s ", class_, method);
switch (line) {
case NativeLine:
fprintf(stderr, "(native)\n");
break;
case UnknownLine:
fprintf(stderr, "(unknown line)\n");
break;
default:
fprintf(stderr, "(line %d)\n", line);
}
return true;
}
Thread* t;
} v(t);
t->m->processor->walkStack(t, &v);
}