2007-07-06 23:50:26 +00:00
|
|
|
#include "jnienv.h"
|
|
|
|
#include "machine.h"
|
2007-07-14 17:31:01 +00:00
|
|
|
#include "stream.h"
|
|
|
|
#include "constants.h"
|
2007-09-24 01:39:03 +00:00
|
|
|
#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)
|
|
|
|
{
|
|
|
|
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();
|
2007-07-18 01:33:00 +00:00
|
|
|
o->state = Thread::JoinedState;
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->rootThread = o->child;
|
2007-07-07 18:09:16 +00:00
|
|
|
if (o->peer) {
|
|
|
|
o->peer->peer = o->child->peer;
|
|
|
|
o->child->peer = o->peer;
|
|
|
|
}
|
|
|
|
} else if (o->peer) {
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->rootThread = o->peer;
|
2007-07-07 18:09:16 +00:00
|
|
|
} else {
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
assert(t, not find(t->m->rootThread, o));
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-18 21:24:29 +00:00
|
|
|
unsigned
|
|
|
|
footprint(Thread* t)
|
|
|
|
{
|
2007-08-23 02:24:25 +00:00
|
|
|
unsigned n = t->heapOffset + t->heapIndex;
|
2007-08-18 21:24:29 +00:00
|
|
|
|
|
|
|
if (t->large) {
|
|
|
|
n += extendedSize
|
|
|
|
(t, t->large, baseSize(t, t->large, objectClass(t, t->large)));
|
|
|
|
}
|
|
|
|
|
|
|
|
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-09-24 01:39:03 +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) {
|
2007-10-12 17:56:43 +00:00
|
|
|
p->visit(v);
|
2007-07-07 23:47:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Thread* c = t->child; c; c = c->peer) {
|
|
|
|
visitRoots(c, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-29 23:32:23 +00:00
|
|
|
void
|
|
|
|
finalizerTargetUnreachable(Thread* t, object* p, Heap::Visitor* v)
|
|
|
|
{
|
|
|
|
v->visit(&finalizerTarget(t, *p));
|
|
|
|
|
|
|
|
object finalizer = *p;
|
|
|
|
*p = finalizerNext(t, finalizer);
|
2007-09-24 01:39:03 +00:00
|
|
|
finalizerNext(t, finalizer) = t->m->finalizeQueue;
|
|
|
|
t->m->finalizeQueue = finalizer;
|
2007-07-29 23:32:23 +00:00
|
|
|
}
|
|
|
|
|
2007-07-20 01:07:30 +00:00
|
|
|
void
|
|
|
|
referenceTargetUnreachable(Thread* t, object* p, Heap::Visitor* v)
|
|
|
|
{
|
2007-07-29 23:32:23 +00:00
|
|
|
if (DebugReferences) {
|
|
|
|
fprintf(stderr, "target %p unreachable for reference %p\n",
|
|
|
|
jreferenceTarget(t, *p), *p);
|
|
|
|
}
|
2007-07-21 17:50:26 +00:00
|
|
|
|
2007-07-20 01:07:30 +00:00
|
|
|
v->visit(p);
|
|
|
|
jreferenceTarget(t, *p) = 0;
|
|
|
|
|
2007-07-20 03:18:25 +00:00
|
|
|
if (jreferenceQueue(t, *p)
|
2007-09-24 01:39:03 +00:00
|
|
|
and t->m->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable)
|
2007-07-20 03:18:25 +00:00
|
|
|
{
|
2007-07-20 01:07:30 +00:00
|
|
|
// queue is reachable - add the reference
|
|
|
|
|
|
|
|
v->visit(&jreferenceQueue(t, *p));
|
|
|
|
|
|
|
|
object q = jreferenceQueue(t, *p);
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, *p, JreferenceJnext, *p);
|
2007-07-20 01:07:30 +00:00
|
|
|
if (referenceQueueFront(t, q)) {
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, referenceQueueRear(t, q), JreferenceJnext, *p);
|
2007-07-20 01:07:30 +00:00
|
|
|
} else {
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, q, ReferenceQueueFront, *p);
|
2007-07-20 01:07:30 +00:00
|
|
|
}
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, q, ReferenceQueueRear, *p);
|
2007-07-20 01:07:30 +00:00
|
|
|
|
|
|
|
jreferenceQueue(t, *p) = 0;
|
|
|
|
}
|
2007-07-29 23:32:23 +00:00
|
|
|
|
|
|
|
*p = jreferenceNext(t, *p);
|
2007-07-20 01:07:30 +00:00
|
|
|
}
|
|
|
|
|
2007-07-20 03:18:25 +00:00
|
|
|
void
|
|
|
|
referenceUnreachable(Thread* t, object* p, Heap::Visitor* v)
|
|
|
|
{
|
2007-07-29 23:32:23 +00:00
|
|
|
if (DebugReferences) {
|
|
|
|
fprintf(stderr, "reference %p unreachable (target %p)\n",
|
|
|
|
*p, jreferenceTarget(t, *p));
|
|
|
|
}
|
2007-07-21 17:50:26 +00:00
|
|
|
|
2007-07-20 03:18:25 +00:00
|
|
|
if (jreferenceQueue(t, *p)
|
2007-09-24 01:39:03 +00:00
|
|
|
and t->m->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable)
|
2007-07-20 03:18:25 +00:00
|
|
|
{
|
|
|
|
// queue is reachable - add the reference
|
|
|
|
referenceTargetUnreachable(t, p, v);
|
2007-07-29 23:32:23 +00:00
|
|
|
} else {
|
|
|
|
*p = jreferenceNext(t, *p);
|
2007-07-20 03:18:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-20 01:07:30 +00:00
|
|
|
void
|
|
|
|
referenceTargetReachable(Thread* t, object* p, Heap::Visitor* v)
|
|
|
|
{
|
2007-07-29 23:32:23 +00:00
|
|
|
if (DebugReferences) {
|
|
|
|
fprintf(stderr, "target %p reachable for reference %p\n",
|
|
|
|
jreferenceTarget(t, *p), *p);
|
|
|
|
}
|
2007-07-21 17:50:26 +00:00
|
|
|
|
2007-07-20 01:07:30 +00:00
|
|
|
v->visit(p);
|
|
|
|
v->visit(&jreferenceTarget(t, *p));
|
|
|
|
|
2007-09-24 01:39:03 +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-10 01:43:43 +00:00
|
|
|
void
|
|
|
|
postVisit(Thread* t, Heap::Visitor* v)
|
|
|
|
{
|
2007-09-24 01:39:03 +00:00
|
|
|
Machine* m = t->m;
|
2007-07-10 01:43:43 +00:00
|
|
|
|
2007-07-29 23:32:23 +00:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2007-07-10 01:43:43 +00:00
|
|
|
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-07-29 23:32:23 +00:00
|
|
|
finalizerTargetUnreachable(t, p, v);
|
2007-07-10 01:43:43 +00:00
|
|
|
} 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) {
|
2007-07-20 03:18:25 +00:00
|
|
|
// reference is unreachable
|
|
|
|
referenceUnreachable(t, p, v);
|
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)
|
|
|
|
{
|
2007-07-20 03:18:25 +00:00
|
|
|
// target is unreachable
|
2007-07-20 01:07:30 +00:00
|
|
|
referenceTargetUnreachable(t, p, v);
|
2007-07-10 01:43:43 +00:00
|
|
|
} else {
|
|
|
|
// both reference and target are reachable
|
2007-07-20 01:07:30 +00:00
|
|
|
referenceTargetReachable(t, p, v);
|
2007-07-10 01:43:43 +00:00
|
|
|
|
|
|
|
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 = jreferenceNext(t, reference);
|
|
|
|
jreferenceNext(t, reference) = firstNewTenuredWeakReference;
|
|
|
|
firstNewTenuredWeakReference = reference;
|
|
|
|
} else {
|
|
|
|
p = &jreferenceNext(t, *p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m->heap->collectionType() == Heap::MajorCollection) {
|
|
|
|
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-07-29 23:32:23 +00:00
|
|
|
finalizerTargetUnreachable(t, p, v);
|
2007-07-10 01:43:43 +00:00
|
|
|
} 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) {
|
2007-07-20 03:18:25 +00:00
|
|
|
// reference is unreachable
|
|
|
|
referenceUnreachable(t, p, v);
|
2007-08-14 01:44:47 +00:00
|
|
|
} else if (m->heap->status(jreferenceTarget(t, *p))
|
2007-07-10 01:43:43 +00:00
|
|
|
== Heap::Unreachable)
|
|
|
|
{
|
2007-07-20 03:18:25 +00:00
|
|
|
// target is unreachable
|
2007-07-20 01:07:30 +00:00
|
|
|
referenceTargetUnreachable(t, p, v);
|
2007-07-10 01:43:43 +00:00
|
|
|
} else {
|
2007-07-20 03:18:25 +00:00
|
|
|
// both reference and target are reachable
|
2007-07-20 01:07:30 +00:00
|
|
|
referenceTargetReachable(t, p, v);
|
2007-07-10 01:43:43 +00:00
|
|
|
p = &jreferenceNext(t, *p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lastNewTenuredFinalizer) {
|
|
|
|
finalizerNext(t, lastNewTenuredFinalizer) = m->tenuredFinalizers;
|
2007-07-11 13:35:28 +00:00
|
|
|
m->tenuredFinalizers = firstNewTenuredFinalizer;
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lastNewTenuredWeakReference) {
|
|
|
|
jreferenceNext(t, lastNewTenuredWeakReference) = m->tenuredWeakReferences;
|
2007-07-11 13:35:28 +00:00
|
|
|
m->tenuredWeakReferences = firstNewTenuredWeakReference;
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-07 23:47:35 +00:00
|
|
|
void
|
|
|
|
postCollect(Thread* t)
|
|
|
|
{
|
2007-07-16 23:58:37 +00:00
|
|
|
#ifdef VM_STRESS
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->system->free(t->defaultHeap);
|
2007-09-13 03:15:16 +00:00
|
|
|
t->defaultHeap = static_cast<uintptr_t*>
|
2007-09-24 01:39:03 +00:00
|
|
|
(t->m->system->allocate(Thread::HeapSizeInBytes));
|
2007-07-16 23:58:37 +00:00
|
|
|
#endif
|
|
|
|
|
2007-08-22 14:50:29 +00:00
|
|
|
t->heap = t->defaultHeap;
|
2007-08-23 02:24:25 +00:00
|
|
|
t->heapOffset = 0;
|
2007-08-22 14:50:29 +00:00
|
|
|
t->heapIndex = 0;
|
|
|
|
|
2007-07-07 23:47:35 +00:00
|
|
|
if (t->large) {
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->system->free(t->large);
|
2007-07-07 23:47:35 +00:00
|
|
|
t->large = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
static const unsigned Size = 256;
|
|
|
|
char buffer[Size];
|
|
|
|
|
|
|
|
vsnprintf(buffer, Size - 1, format, a);
|
|
|
|
|
|
|
|
object s = makeByteArray(t, strlen(buffer) + 1, false);
|
|
|
|
memcpy(&byteArrayBody(t, s, 0), buffer, byteArrayLength(t, s));
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned
|
|
|
|
mangledSize(int8_t c)
|
|
|
|
{
|
|
|
|
switch (c) {
|
|
|
|
case '_':
|
|
|
|
case ';':
|
|
|
|
case '[':
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
case '$':
|
|
|
|
return 6;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
mangle(int8_t c, int8_t* dst)
|
|
|
|
{
|
|
|
|
switch (c) {
|
|
|
|
case '/':
|
|
|
|
dst[0] = '_';
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
case '_':
|
|
|
|
dst[0] = '_';
|
|
|
|
dst[1] = '1';
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
case ';':
|
|
|
|
dst[0] = '_';
|
|
|
|
dst[1] = '2';
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
case '[':
|
|
|
|
dst[0] = '_';
|
|
|
|
dst[1] = '3';
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
case '$':
|
|
|
|
memcpy(dst, "_00024", 6);
|
|
|
|
return 6;
|
|
|
|
|
|
|
|
default:
|
|
|
|
dst[0] = c;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeJNIName(Thread* t, object method, bool decorate)
|
|
|
|
{
|
|
|
|
unsigned size = 5;
|
|
|
|
object className = ::className(t, methodClass(t, method));
|
|
|
|
PROTECT(t, className);
|
|
|
|
for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) {
|
|
|
|
size += mangledSize(byteArrayBody(t, className, i));
|
|
|
|
}
|
|
|
|
|
|
|
|
++ size;
|
|
|
|
|
|
|
|
object methodName = ::methodName(t, method);
|
|
|
|
PROTECT(t, methodName);
|
|
|
|
for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) {
|
|
|
|
size += mangledSize(byteArrayBody(t, methodName, i));
|
|
|
|
}
|
|
|
|
|
|
|
|
object methodSpec = ::methodSpec(t, method);
|
|
|
|
PROTECT(t, methodSpec);
|
|
|
|
if (decorate) {
|
|
|
|
size += 2;
|
|
|
|
for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1
|
|
|
|
and byteArrayBody(t, methodSpec, i) != ')'; ++i)
|
|
|
|
{
|
|
|
|
size += mangledSize(byteArrayBody(t, methodSpec, i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object name = makeByteArray(t, size + 1, false);
|
|
|
|
unsigned index = 0;
|
|
|
|
|
|
|
|
memcpy(&byteArrayBody(t, name, index), "Java_", 5);
|
|
|
|
index += 5;
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) {
|
|
|
|
index += mangle(byteArrayBody(t, className, i),
|
|
|
|
&byteArrayBody(t, name, index));
|
|
|
|
}
|
|
|
|
|
|
|
|
byteArrayBody(t, name, index++) = '_';
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) {
|
|
|
|
index += mangle(byteArrayBody(t, methodName, i),
|
|
|
|
&byteArrayBody(t, name, index));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (decorate) {
|
|
|
|
byteArrayBody(t, name, index++) = '_';
|
|
|
|
byteArrayBody(t, name, index++) = '_';
|
|
|
|
for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1
|
|
|
|
and byteArrayBody(t, methodSpec, i) != ')'; ++i)
|
|
|
|
{
|
2007-07-27 00:06:05 +00:00
|
|
|
index += mangle(byteArrayBody(t, methodSpec, i),
|
2007-07-14 17:31:01 +00:00
|
|
|
&byteArrayBody(t, name, index));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
byteArrayBody(t, name, index++) = 0;
|
|
|
|
|
|
|
|
assert(t, index == size + 1);
|
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2007-10-24 21:05:15 +00:00
|
|
|
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) {
|
2007-10-24 21:05:15 +00:00
|
|
|
unsigned a = s.read1();
|
|
|
|
if (a & 0x80) {
|
|
|
|
++ si;
|
|
|
|
assert(t, si < length);
|
|
|
|
|
|
|
|
unsigned b = s.read1();
|
|
|
|
|
|
|
|
if (a == 0xC0 and b == 0x80) {
|
2007-10-24 23:05:14 +00:00
|
|
|
byteArrayBody(t, value, vi++) = 0;
|
2007-10-24 21:05:15 +00:00
|
|
|
} else {
|
2007-10-25 19:20:39 +00:00
|
|
|
abort(t); // todo: handle non-ASCII characters
|
2007-10-24 21:05:15 +00:00
|
|
|
}
|
|
|
|
} else {
|
2007-10-24 23:05:14 +00:00
|
|
|
byteArrayBody(t, value, vi++) = a;
|
2007-10-24 21:05:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
object
|
|
|
|
parsePool(Thread* t, Stream& s)
|
|
|
|
{
|
|
|
|
unsigned poolCount = s.read2() - 1;
|
|
|
|
object pool = makeArray(t, poolCount, true);
|
|
|
|
|
|
|
|
PROTECT(t, pool);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < poolCount; ++i) {
|
|
|
|
unsigned c = s.read1();
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case CONSTANT_Integer: {
|
|
|
|
object value = makeInt(t, s.read4());
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
2007-07-14 17:31:01 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_Float: {
|
2007-10-25 19:20:39 +00:00
|
|
|
object value = makeInt(t, s.readFloat());
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
2007-07-14 17:31:01 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_Long: {
|
|
|
|
object value = makeLong(t, s.read8());
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
2007-07-14 17:31:01 +00:00
|
|
|
++i;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_Double: {
|
2007-10-25 19:20:39 +00:00
|
|
|
object value = makeLong(t, s.readDouble());
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
2007-07-14 17:31:01 +00:00
|
|
|
++i;
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_Utf8: {
|
2007-10-24 21:05:15 +00:00
|
|
|
object value = parseUtf8(t, s, s.read2());
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
2007-07-14 17:31:01 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_Class: {
|
|
|
|
object value = makeIntArray(t, 2, false);
|
|
|
|
intArrayBody(t, value, 0) = c;
|
|
|
|
intArrayBody(t, value, 1) = s.read2();
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
2007-07-14 17:31:01 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_String: {
|
|
|
|
object value = makeIntArray(t, 2, false);
|
|
|
|
intArrayBody(t, value, 0) = c;
|
|
|
|
intArrayBody(t, value, 1) = s.read2();
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
2007-07-14 17:31:01 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_NameAndType: {
|
|
|
|
object value = makeIntArray(t, 3, false);
|
|
|
|
intArrayBody(t, value, 0) = c;
|
|
|
|
intArrayBody(t, value, 1) = s.read2();
|
|
|
|
intArrayBody(t, value, 2) = s.read2();
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
2007-07-14 17:31:01 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_Fieldref:
|
|
|
|
case CONSTANT_Methodref:
|
|
|
|
case CONSTANT_InterfaceMethodref: {
|
|
|
|
object value = makeIntArray(t, 3, false);
|
|
|
|
intArrayBody(t, value, 0) = c;
|
|
|
|
intArrayBody(t, value, 1) = s.read2();
|
|
|
|
intArrayBody(t, value, 2) = s.read2();
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
2007-07-14 17:31:01 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < poolCount; ++i) {
|
|
|
|
object o = arrayBody(t, pool, i);
|
|
|
|
if (o and objectClass(t, o)
|
2007-09-24 01:39:03 +00:00
|
|
|
== arrayBody(t, t->m->types, Machine::IntArrayType))
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
|
|
|
switch (intArrayBody(t, o, 0)) {
|
|
|
|
case CONSTANT_Class: {
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, pool, ArrayBody + (i * BytesPerWord),
|
2007-07-14 17:31:01 +00:00
|
|
|
arrayBody(t, pool, intArrayBody(t, o, 1) - 1));
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_String: {
|
|
|
|
object bytes = arrayBody(t, pool, intArrayBody(t, o, 1) - 1);
|
|
|
|
object value = makeString
|
|
|
|
(t, bytes, 0, byteArrayLength(t, bytes) - 1, 0);
|
2007-07-29 00:02:32 +00:00
|
|
|
value = intern(t, value);
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
2007-07-14 17:31:01 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_NameAndType: {
|
|
|
|
object name = arrayBody(t, pool, intArrayBody(t, o, 1) - 1);
|
|
|
|
object type = arrayBody(t, pool, intArrayBody(t, o, 2) - 1);
|
|
|
|
object value = makePair(t, name, type);
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
2007-07-14 17:31:01 +00:00
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < poolCount; ++i) {
|
|
|
|
object o = arrayBody(t, pool, i);
|
|
|
|
if (o and objectClass(t, o)
|
2007-09-24 01:39:03 +00:00
|
|
|
== arrayBody(t, t->m->types, Machine::IntArrayType))
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
|
|
|
switch (intArrayBody(t, o, 0)) {
|
|
|
|
case CONSTANT_Fieldref:
|
|
|
|
case CONSTANT_Methodref:
|
|
|
|
case CONSTANT_InterfaceMethodref: {
|
|
|
|
object c = arrayBody(t, pool, intArrayBody(t, o, 1) - 1);
|
|
|
|
object nameAndType = arrayBody(t, pool, intArrayBody(t, o, 2) - 1);
|
|
|
|
object value = makeReference
|
|
|
|
(t, c, pairFirst(t, nameAndType), pairSecond(t, nameAndType));
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, pool, ArrayBody + (i * BytesPerWord), value);
|
2007-07-14 17:31:01 +00:00
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
2007-07-29 18:52:08 +00:00
|
|
|
object map = makeHashMap(t, 0, 0);
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, map);
|
|
|
|
|
|
|
|
if (classSuper(t, class_)) {
|
|
|
|
addInterfaces(t, classSuper(t, class_), map);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned count = s.read2();
|
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
|
|
object name = arrayBody(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;
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, interfaceTable, ArrayBody + (i * BytesPerWord), interface);
|
|
|
|
++ i;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, interfaceTable, ArrayBody + (i * BytesPerWord), vtable);
|
2007-08-14 00:37:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
++i;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, class_, ClassInterfaceTable, interfaceTable);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
|
|
|
unsigned staticOffset = 0;
|
|
|
|
|
|
|
|
object fieldTable = makeArray(t, count, true);
|
|
|
|
PROTECT(t, fieldTable);
|
|
|
|
|
2007-10-25 19:20:39 +00:00
|
|
|
object staticValueTable = makeArray(t, count, true);
|
|
|
|
PROTECT(t, staticValueTable);
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
|
|
unsigned flags = s.read2();
|
|
|
|
unsigned name = s.read2();
|
|
|
|
unsigned spec = s.read2();
|
|
|
|
|
2007-10-25 19:20:39 +00:00
|
|
|
object value = 0;
|
|
|
|
PROTECT(t, value);
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned attributeCount = s.read2();
|
|
|
|
for (unsigned j = 0; j < attributeCount; ++j) {
|
2007-10-25 19:20:39 +00:00
|
|
|
object name = arrayBody(t, pool, s.read2() - 1);
|
|
|
|
unsigned length = s.read4();
|
|
|
|
|
|
|
|
if (strcmp(reinterpret_cast<const int8_t*>("ConstantValue"),
|
|
|
|
&byteArrayBody(t, name, 0)) == 0)
|
|
|
|
{
|
|
|
|
value = arrayBody(t, pool, s.read2() - 1);
|
|
|
|
} else {
|
|
|
|
s.skip(length);
|
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object field = makeField
|
|
|
|
(t,
|
2007-07-21 17:50:26 +00:00
|
|
|
0, // vm flags
|
|
|
|
fieldCode(t, byteArrayBody(t, arrayBody(t, pool, spec - 1), 0)),
|
2007-07-14 17:31:01 +00:00
|
|
|
flags,
|
|
|
|
0, // offset
|
|
|
|
arrayBody(t, pool, name - 1),
|
|
|
|
arrayBody(t, pool, spec - 1),
|
|
|
|
class_);
|
|
|
|
|
|
|
|
if (flags & ACC_STATIC) {
|
2007-10-25 19:20:39 +00:00
|
|
|
set(t, staticValueTable, ArrayBody + (staticOffset * BytesPerWord),
|
|
|
|
value);
|
2007-07-14 17:31:01 +00:00
|
|
|
fieldOffset(t, field) = staticOffset++;
|
|
|
|
} else {
|
2007-10-25 19:20:39 +00:00
|
|
|
if (value) {
|
|
|
|
abort(t); // todo: handle non-static field initializers
|
|
|
|
}
|
|
|
|
|
2007-10-17 01:20:36 +00:00
|
|
|
unsigned excess = memberOffset % fieldSize(t, field);
|
|
|
|
if (excess) {
|
2007-07-14 17:31:01 +00:00
|
|
|
memberOffset += BytesPerWord - excess;
|
|
|
|
}
|
|
|
|
|
|
|
|
fieldOffset(t, field) = memberOffset;
|
|
|
|
memberOffset += fieldSize(t, field);
|
|
|
|
}
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, fieldTable, ArrayBody + (i * BytesPerWord), field);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, class_, ClassFieldTable, fieldTable);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
|
|
|
if (staticOffset) {
|
2007-10-25 19:20:39 +00:00
|
|
|
object staticTable = makeArray(t, staticOffset, false);
|
|
|
|
memcpy(&arrayBody(t, staticTable, 0),
|
|
|
|
&arrayBody(t, staticValueTable, 0),
|
|
|
|
staticOffset * BytesPerWord);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, class_, ClassStaticTable, staticTable);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
classFixedSize(t, class_) = pad(memberOffset);
|
|
|
|
|
|
|
|
if (classSuper(t, class_)
|
|
|
|
and memberOffset == classFixedSize(t, classSuper(t, class_)))
|
|
|
|
{
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, class_, ClassObjectMask,
|
2007-07-14 17:31:01 +00:00
|
|
|
classObjectMask(t, classSuper(t, class_)));
|
|
|
|
} else {
|
|
|
|
object mask = makeIntArray
|
2007-09-13 00:21:37 +00:00
|
|
|
(t, ceiling(classFixedSize(t, class_), 32 * BytesPerWord), true);
|
2007-07-14 17:31:01 +00:00
|
|
|
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_)),
|
2007-09-15 17:22:22 +00:00
|
|
|
32 * BytesPerWord)
|
2007-08-14 00:37:00 +00:00
|
|
|
* 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
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-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-14 00:37:00 +00:00
|
|
|
if (superMask or sawReferenceField) {
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, class_, ClassObjectMask, mask);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
parseCode(Thread* t, Stream& s, object pool)
|
|
|
|
{
|
2007-07-19 23:45:44 +00:00
|
|
|
PROTECT(t, pool);
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
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);
|
2007-07-16 23:58:37 +00:00
|
|
|
PROTECT(t, code);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, code, CodeExceptionHandlerTable, eht);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned attributeCount = s.read2();
|
|
|
|
for (unsigned j = 0; j < attributeCount; ++j) {
|
|
|
|
object name = arrayBody(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();
|
|
|
|
}
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, code, CodeLineNumberTable, lnt);
|
2007-07-14 17:31:01 +00:00
|
|
|
} else {
|
|
|
|
s.skip(length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return code;
|
|
|
|
}
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
void
|
|
|
|
scanMethodSpec(Thread* t, const char* s, unsigned* parameterCount,
|
|
|
|
unsigned* returnCode)
|
|
|
|
{
|
|
|
|
unsigned count = 0;
|
2007-09-28 23:41:03 +00:00
|
|
|
MethodSpecIterator it(t, s);
|
|
|
|
for (; it.hasNext(); it.next()) {
|
2007-09-26 23:23:03 +00:00
|
|
|
++ count;
|
|
|
|
}
|
|
|
|
|
|
|
|
*parameterCount = count;
|
2007-09-28 23:41:03 +00:00
|
|
|
*returnCode = fieldCode(t, *it.returnSpec());
|
2007-09-26 23:23:03 +00:00
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
void
|
|
|
|
parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
|
|
|
{
|
|
|
|
PROTECT(t, class_);
|
|
|
|
PROTECT(t, pool);
|
|
|
|
|
2007-07-29 18:52:08 +00:00
|
|
|
object virtualMap = makeHashMap(t, 0, 0);
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, virtualMap);
|
|
|
|
|
2007-07-29 18:52:08 +00:00
|
|
|
object nativeMap = makeHashMap(t, 0, 0);
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, nativeMap);
|
|
|
|
|
|
|
|
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);
|
2007-07-14 17:31:01 +00:00
|
|
|
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),
|
2007-09-26 23:23:03 +00:00
|
|
|
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),
|
2007-10-12 17:56:43 +00:00
|
|
|
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);
|
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} 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 = arrayBody(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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
const char* specString = reinterpret_cast<const char*>
|
|
|
|
(&byteArrayBody(t, arrayBody(t, pool, spec - 1), 0));
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
unsigned parameterCount;
|
|
|
|
unsigned returnCode;
|
|
|
|
scanMethodSpec(t, specString, ¶meterCount, &returnCode);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
unsigned parameterFootprint = t->m->processor->parameterFootprint
|
|
|
|
(t, specString, flags & ACC_STATIC);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-10-04 00:41:54 +00:00
|
|
|
Compiled* compiled;
|
2007-10-01 15:19:15 +00:00
|
|
|
if (flags & ACC_NATIVE) {
|
2007-10-04 00:41:54 +00:00
|
|
|
compiled = static_cast<Compiled*>(t->m->processor->nativeInvoker(t));
|
2007-10-01 15:19:15 +00:00
|
|
|
} else {
|
2007-10-04 00:41:54 +00:00
|
|
|
compiled = static_cast<Compiled*>(t->m->processor->methodStub(t));
|
2007-10-01 15:19:15 +00:00
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
object method = makeMethod(t,
|
2007-07-21 17:50:26 +00:00
|
|
|
0, // vm flags
|
2007-09-26 23:23:03 +00:00
|
|
|
returnCode,
|
2007-07-14 17:31:01 +00:00
|
|
|
parameterCount,
|
|
|
|
parameterFootprint,
|
2007-07-21 17:50:26 +00:00
|
|
|
flags,
|
|
|
|
0, // offset
|
2007-07-14 17:31:01 +00:00
|
|
|
arrayBody(t, pool, name - 1),
|
|
|
|
arrayBody(t, pool, spec - 1),
|
|
|
|
class_,
|
2007-09-25 23:53:11 +00:00
|
|
|
code,
|
2007-10-04 00:41:54 +00:00
|
|
|
reinterpret_cast<uint64_t>(compiled));
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, method);
|
|
|
|
|
|
|
|
if (flags & ACC_STATIC) {
|
2007-09-13 03:15:16 +00:00
|
|
|
methodOffset(t, method) = i;
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
if (strcmp(reinterpret_cast<const int8_t*>("<clinit>"),
|
|
|
|
&byteArrayBody(t, methodName(t, method), 0)) == 0)
|
|
|
|
{
|
2007-08-01 23:48:36 +00:00
|
|
|
methodVmFlags(t, method) |= ClassInitFlag;
|
2007-07-28 16:10:13 +00:00
|
|
|
classVmFlags(t, class_) |= NeedInitFlag;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
++ declaredVirtualCount;
|
|
|
|
|
|
|
|
object p = hashMapFindNode
|
|
|
|
(t, virtualMap, method, methodHash, methodEqual);
|
|
|
|
|
|
|
|
if (p) {
|
|
|
|
methodOffset(t, method) = methodOffset(t, tripleFirst(t, p));
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, p, TripleSecond, method);
|
2007-07-14 17:31:01 +00:00
|
|
|
} else {
|
|
|
|
methodOffset(t, method) = virtualCount++;
|
|
|
|
|
|
|
|
listAppend(t, newVirtuals, method);
|
|
|
|
|
|
|
|
hashMapInsert(t, virtualMap, method, method, methodHash);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & ACC_NATIVE) {
|
|
|
|
object p = hashMapFindNode
|
2007-07-27 00:06:05 +00:00
|
|
|
(t, nativeMap, methodName(t, method), byteArrayHash, byteArrayEqual);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
|
|
|
if (p) {
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, p, TripleSecond, method);
|
2007-07-14 17:31:01 +00:00
|
|
|
} else {
|
2007-07-27 00:06:05 +00:00
|
|
|
hashMapInsert(t, nativeMap, methodName(t, method), 0, byteArrayHash);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, methodTable, ArrayBody + (i * BytesPerWord), method);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
|
|
object method = arrayBody(t, methodTable, i);
|
|
|
|
|
|
|
|
if (methodFlags(t, method) & ACC_NATIVE) {
|
2007-07-17 13:22:29 +00:00
|
|
|
PROTECT(t, method);
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
object overloaded = hashMapFind
|
2007-07-27 00:06:05 +00:00
|
|
|
(t, nativeMap, methodName(t, method), byteArrayHash, byteArrayEqual);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
|
|
|
object jniName = makeJNIName(t, method, overloaded);
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, method, MethodCode, jniName);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, class_, ClassMethodTable, methodTable);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2007-08-14 13:27:10 +00:00
|
|
|
if (declaredVirtualCount == 0
|
|
|
|
and (classFlags(t, class_) & ACC_INTERFACE) == 0)
|
|
|
|
{
|
2007-07-14 17:31:01 +00:00
|
|
|
// inherit interface table and virtual table from superclass
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, class_, ClassInterfaceTable,
|
2007-07-14 17:31:01 +00:00
|
|
|
classInterfaceTable(t, classSuper(t, class_)));
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, class_, ClassVirtualTable, superVirtualTable);
|
2007-07-14 17:31:01 +00:00
|
|
|
} else if (virtualCount) {
|
|
|
|
// generate class vtable
|
|
|
|
|
2007-07-17 13:22:29 +00:00
|
|
|
object vtable = makeArray(t, virtualCount, true);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-08-14 00:37:00 +00:00
|
|
|
unsigned i = 0;
|
2007-07-14 17:31:01 +00:00
|
|
|
if (classFlags(t, class_) & ACC_INTERFACE) {
|
2007-07-16 23:58:37 +00:00
|
|
|
PROTECT(t, vtable);
|
|
|
|
|
2007-08-14 00:37:00 +00:00
|
|
|
for (object it = hashMapIterator(t, virtualMap); it;
|
|
|
|
it = hashMapIteratorNext(t, it))
|
|
|
|
{
|
2007-07-14 17:31:01 +00:00
|
|
|
object method = tripleFirst(t, hashMapIteratorNode(t, it));
|
2007-08-14 00:37:00 +00:00
|
|
|
assert(t, arrayBody(t, vtable, methodOffset(t, method)) == 0);
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, vtable, ArrayBody + (methodOffset(t, method) * BytesPerWord),
|
|
|
|
method);
|
2007-08-14 00:37:00 +00:00
|
|
|
++ i;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (superVirtualTable) {
|
|
|
|
for (; i < arrayLength(t, superVirtualTable); ++i) {
|
|
|
|
object method = arrayBody(t, superVirtualTable, i);
|
|
|
|
method = hashMapFind(t, virtualMap, method, methodHash, methodEqual);
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, vtable, ArrayBody + (i * BytesPerWord), method);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) {
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, vtable, ArrayBody + (i * BytesPerWord), pairFirst(t, p));
|
|
|
|
++ i;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-14 00:37:00 +00:00
|
|
|
assert(t, arrayLength(t, vtable) == i);
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, class_, ClassVirtualTable, vtable);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
|
|
|
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
|
|
|
|
// 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));
|
2007-08-14 00:37:00 +00:00
|
|
|
if (ivtable) {
|
|
|
|
object vtable = arrayBody(t, itable, i + 1);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-08-14 00:37:00 +00:00
|
|
|
for (unsigned j = 0; j < arrayLength(t, ivtable); ++j) {
|
|
|
|
object method = arrayBody(t, ivtable, j);
|
|
|
|
method = hashMapFind
|
|
|
|
(t, virtualMap, method, methodHash, methodEqual);
|
|
|
|
assert(t, method);
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, vtable, ArrayBody + (j * BytesPerWord), method);
|
2007-08-14 00:37:00 +00:00
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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, classFixedSize(t, bootstrapClass) == classFixedSize(t, class_));
|
2007-07-20 03:18:25 +00:00
|
|
|
expect(t,
|
|
|
|
(classVmFlags(t, bootstrapClass) & ReferenceFlag)
|
|
|
|
or (classObjectMask(t, bootstrapClass) == 0
|
2007-07-14 17:31:01 +00:00
|
|
|
and classObjectMask(t, class_) == 0)
|
|
|
|
or intArrayEqual(t, classObjectMask(t, bootstrapClass),
|
|
|
|
classObjectMask(t, class_)));
|
|
|
|
|
|
|
|
PROTECT(t, bootstrapClass);
|
|
|
|
PROTECT(t, class_);
|
|
|
|
|
|
|
|
ENTER(t, Thread::ExclusiveState);
|
|
|
|
|
2007-07-16 23:58:37 +00:00
|
|
|
classFlags(t, bootstrapClass) = classFlags(t, class_);
|
2007-07-28 16:10:13 +00:00
|
|
|
classVmFlags(t, bootstrapClass) |= classVmFlags(t, class_);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
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_));
|
2007-07-14 17:31:01 +00:00
|
|
|
|
|
|
|
object fieldTable = classFieldTable(t, class_);
|
|
|
|
if (fieldTable) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, fieldTable); ++i) {
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, arrayBody(t, fieldTable, i), FieldClass, bootstrapClass);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object methodTable = classMethodTable(t, class_);
|
|
|
|
if (methodTable) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, methodTable); ++i) {
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, arrayBody(t, methodTable, i), MethodClass, bootstrapClass);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2007-07-14 17:31:01 +00:00
|
|
|
return makeClass
|
|
|
|
(t,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
dimensions,
|
|
|
|
2 * BytesPerWord,
|
|
|
|
BytesPerWord,
|
2007-09-24 01:39:03 +00:00
|
|
|
classObjectMask(t, arrayBody(t, t->m->types, Machine::ArrayType)),
|
2007-07-14 17:31:01 +00:00
|
|
|
spec,
|
2007-09-24 01:39:03 +00:00
|
|
|
arrayBody(t, t->m->types, Machine::JobjectType),
|
2007-07-14 17:31:01 +00:00
|
|
|
0,
|
2007-09-24 01:39:03 +00:00
|
|
|
classVirtualTable(t, arrayBody(t, t->m->types, Machine::JobjectType)),
|
2007-07-14 17:31:01 +00:00
|
|
|
0,
|
2007-07-30 23:19:05 +00:00
|
|
|
0,
|
2007-08-20 02:57:32 +00:00
|
|
|
elementClass,
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->loader);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-14 18:37:04 +00:00
|
|
|
object elementClass = hashMapFind
|
2007-09-24 01:39:03 +00:00
|
|
|
(t, t->m->bootstrapClassMap, elementSpec, byteArrayHash, byteArrayEqual);
|
2007-07-14 18:37:04 +00:00
|
|
|
|
|
|
|
if (elementClass == 0) {
|
|
|
|
elementClass = resolveClass(t, elementSpec);
|
|
|
|
if (UNLIKELY(t->exception)) return 0;
|
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
|
|
|
|
return makeArrayClass(t, dimensions, spec, elementClass);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
removeMonitor(Thread* t, object o)
|
|
|
|
{
|
2007-09-24 01:39:03 +00:00
|
|
|
object p = hashMapRemove(t, t->m->monitorMap, o, objectHash, objectEqual);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
|
|
|
assert(t, p);
|
|
|
|
|
|
|
|
if (DebugMonitors) {
|
|
|
|
fprintf(stderr, "dispose monitor %p for object %x\n",
|
|
|
|
static_cast<System::Monitor*>(pointerValue(t, p)),
|
|
|
|
objectHash(t, o));
|
|
|
|
}
|
|
|
|
|
|
|
|
static_cast<System::Monitor*>(pointerValue(t, p))->dispose();
|
|
|
|
}
|
|
|
|
|
2007-07-29 00:02:32 +00:00
|
|
|
void
|
|
|
|
removeString(Thread* t, object o)
|
|
|
|
{
|
2007-09-24 01:39:03 +00:00
|
|
|
hashMapRemove(t, t->m->stringMap, o, stringHash, objectEqual);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
invoke(Thread* t, const char* className, int argc, const char** argv)
|
|
|
|
{
|
|
|
|
enter(t, Thread::ActiveState);
|
|
|
|
|
|
|
|
object args = makeObjectArray
|
|
|
|
(t, arrayBody(t, t->m->types, Machine::StringType), argc, true);
|
|
|
|
|
|
|
|
PROTECT(t, args);
|
|
|
|
|
|
|
|
for (int i = 0; i < argc; ++i) {
|
|
|
|
object arg = makeString(t, "%s", argv[i]);
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, args, ArrayBody + (i * BytesPerWord), arg);
|
2007-09-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
t->m->processor->invoke
|
|
|
|
(t, className, "main", "([Ljava/lang/String;)V", 0, args);
|
2007-07-29 00:02:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace vm {
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
Machine::Machine(System* system, Heap* heap, Finder* finder,
|
|
|
|
Processor* processor):
|
2007-09-10 23:33:58 +00:00
|
|
|
vtable(&javaVMVTable),
|
2007-07-06 23:50:26 +00:00
|
|
|
system(system),
|
|
|
|
heap(heap),
|
2007-08-10 23:45:47 +00:00
|
|
|
finder(finder),
|
2007-09-24 01:39:03 +00:00
|
|
|
processor(processor),
|
2007-07-06 23:50:26 +00:00
|
|
|
rootThread(0),
|
|
|
|
exclusive(0),
|
2007-09-07 23:20:21 +00:00
|
|
|
jniReferences(0),
|
2007-10-25 18:33:43 +00:00
|
|
|
builtins(0),
|
2007-07-06 23:50:26 +00:00
|
|
|
activeCount(0),
|
|
|
|
liveCount(0),
|
2007-09-10 23:33:58 +00:00
|
|
|
localThread(0),
|
2007-07-06 23:50:26 +00:00
|
|
|
stateLock(0),
|
|
|
|
heapLock(0),
|
|
|
|
classLock(0),
|
2007-07-20 03:18:25 +00:00
|
|
|
referenceLock(0),
|
2007-07-06 23:50:26 +00:00
|
|
|
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),
|
2007-07-10 01:43:43 +00:00
|
|
|
tenuredFinalizers(0),
|
|
|
|
finalizeQueue(0),
|
2007-07-10 03:04:49 +00:00
|
|
|
weakReferences(0),
|
2007-07-10 01:43:43 +00:00
|
|
|
tenuredWeakReferences(0),
|
2007-08-22 14:50:29 +00:00
|
|
|
unsafe(false),
|
|
|
|
heapPoolIndex(0)
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
2007-09-10 23:33:58 +00:00
|
|
|
populateJNITables(&javaVMVTable, &jniEnvVTable);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-09-10 23:33:58 +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
|
2007-09-18 23:30:09 +00:00
|
|
|
not system->success(system->make(&referenceLock)) or
|
|
|
|
not system->success(system->load(&libraries, 0, false, 0)))
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
|
|
|
system->abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Machine::dispose()
|
|
|
|
{
|
2007-09-10 23:33:58 +00:00
|
|
|
localThread->dispose();
|
2007-07-06 23:50:26 +00:00
|
|
|
stateLock->dispose();
|
|
|
|
heapLock->dispose();
|
|
|
|
classLock->dispose();
|
2007-07-20 03:18:25 +00:00
|
|
|
referenceLock->dispose();
|
2007-07-06 23:50:26 +00:00
|
|
|
|
|
|
|
if (libraries) {
|
|
|
|
libraries->dispose();
|
|
|
|
}
|
2007-09-07 23:20:21 +00:00
|
|
|
|
|
|
|
for (Reference* r = jniReferences; r;) {
|
|
|
|
Reference* t = r;
|
|
|
|
r = r->next;
|
|
|
|
system->free(t);
|
|
|
|
}
|
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)),
|
2007-09-24 01:39:03 +00:00
|
|
|
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),
|
2007-07-07 18:09:16 +00:00
|
|
|
large(0),
|
2007-07-06 23:50:26 +00:00
|
|
|
heapIndex(0),
|
2007-08-23 02:24:25 +00:00
|
|
|
heapOffset(0),
|
2007-07-28 21:28:25 +00:00
|
|
|
protector(0),
|
2007-10-14 01:18:25 +00:00
|
|
|
runnable(this),
|
|
|
|
defaultHeap(static_cast<uintptr_t*>(m->system->allocate(HeapSizeInBytes))),
|
|
|
|
heap(defaultHeap)
|
2007-07-16 23:58:37 +00:00
|
|
|
#ifdef VM_STRESS
|
2007-10-14 01:18:25 +00:00
|
|
|
, stress(false)
|
2007-07-16 23:58:37 +00:00
|
|
|
#endif // VM_STRESS
|
2007-10-25 22:06:05 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
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-09-24 01:39:03 +00:00
|
|
|
t->m->loader = allocate(t, sizeof(void*) * 3);
|
|
|
|
memset(t->m->loader, 0, sizeof(void*) * 2);
|
2007-07-30 23:19:05 +00:00
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
#include "type-initializations.cpp"
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
object arrayClass = arrayBody(t, t->m->types, Machine::ArrayType);
|
2007-10-22 17:22:30 +00:00
|
|
|
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
|
2007-09-24 01:39:03 +00:00
|
|
|
(t, t->m->types, Machine::SystemClassLoaderType);
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, t->m->loader, 0, loaderClass);
|
2007-07-30 23:19:05 +00:00
|
|
|
|
2007-07-12 23:46:08 +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);
|
2007-10-22 17:22:30 +00:00
|
|
|
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);
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, intArrayClass, 0, classClass);
|
|
|
|
set(t, intArrayClass, ClassSuper, objectClass);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
|
|
|
m->unsafe = false;
|
|
|
|
|
2007-07-20 03:18:25 +00:00
|
|
|
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;
|
|
|
|
|
2007-08-18 17:53:30 +00:00
|
|
|
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;
|
|
|
|
|
2007-07-29 18:52:08 +00:00
|
|
|
m->bootstrapClassMap = makeHashMap(this, 0, 0);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-07-30 23:19:05 +00:00
|
|
|
object loaderMap = makeHashMap(this, 0, 0);
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, m->loader, SystemClassLoaderMap, loaderMap);
|
2007-07-30 23:19:05 +00:00
|
|
|
|
2007-07-29 18:52:08 +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);
|
|
|
|
|
2007-09-10 23:33:58 +00:00
|
|
|
m->localThread->set(this);
|
2007-09-30 02:48:27 +00:00
|
|
|
|
|
|
|
#include "type-java-initializations.cpp"
|
|
|
|
|
|
|
|
enter(t, Thread::ActiveState);
|
|
|
|
|
2007-09-30 16:32:17 +00:00
|
|
|
resolveClass
|
|
|
|
(t, className(t, arrayBody(t, m->types,
|
|
|
|
Machine::SystemClassLoaderType)));
|
2007-09-30 02:48:27 +00:00
|
|
|
resolveClass
|
|
|
|
(t, className(t, arrayBody(t, m->types, Machine::ClassType)));
|
|
|
|
resolveClass
|
|
|
|
(t, className(t, arrayBody(t, m->types, Machine::IntArrayType)));
|
|
|
|
resolveClass
|
|
|
|
(t, className(t, arrayBody(t, m->types, Machine::ByteArrayType)));
|
2007-07-07 18:09:16 +00:00
|
|
|
} else {
|
|
|
|
parent->child = this;
|
|
|
|
}
|
2007-09-10 23:33:58 +00:00
|
|
|
|
|
|
|
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-09-30 02:48:27 +00:00
|
|
|
|
2007-09-30 16:32:17 +00:00
|
|
|
if (parent == 0) {
|
|
|
|
enter(this, Thread::IdleState);
|
|
|
|
}
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Thread::exit()
|
|
|
|
{
|
|
|
|
if (state != Thread::ExitState and
|
|
|
|
state != Thread::ZombieState)
|
|
|
|
{
|
|
|
|
enter(this, Thread::ExclusiveState);
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
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 (large) {
|
2007-09-24 01:39:03 +00:00
|
|
|
m->system->free(large);
|
2007-07-07 18:09:16 +00:00
|
|
|
large = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (systemThread) {
|
|
|
|
systemThread->dispose();
|
|
|
|
systemThread = 0;
|
|
|
|
}
|
|
|
|
|
2007-07-17 00:23:23 +00:00
|
|
|
#ifdef VM_STRESS
|
2007-09-24 01:39:03 +00:00
|
|
|
m->system->free(heap);
|
2007-07-17 00:23:23 +00:00
|
|
|
heap = 0;
|
|
|
|
#endif // VM_STRESS
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
m->system->free(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);
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
joinAll(t, t->m->rootThread);
|
2007-07-07 18:09:16 +00:00
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
for (object* p = &(t->m->finalizers); *p;) {
|
2007-07-17 01:55:49 +00:00
|
|
|
object f = *p;
|
|
|
|
*p = finalizerNext(t, *p);
|
|
|
|
|
2007-10-22 20:56:27 +00:00
|
|
|
void (*function)(Thread*, object);
|
|
|
|
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
|
|
|
|
function(t, finalizerTarget(t, f));
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
for (object* p = &(t->m->tenuredFinalizers); *p;) {
|
2007-07-17 01:55:49 +00:00
|
|
|
object f = *p;
|
|
|
|
*p = finalizerNext(t, *p);
|
|
|
|
|
2007-10-22 20:56:27 +00:00
|
|
|
void (*function)(Thread*, object);
|
|
|
|
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
|
|
|
|
function(t, finalizerTarget(t, f));
|
2007-07-11 04:19:26 +00:00
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +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)
|
|
|
|
{
|
2007-07-16 01:03:02 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
ACQUIRE_RAW(t, t->m->stateLock);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
|
|
|
switch (s) {
|
|
|
|
case Thread::ExclusiveState: {
|
2007-07-18 01:33:00 +00:00
|
|
|
assert(t, t->state == Thread::ActiveState);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
t->state = Thread::ExclusiveState;
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->exclusive = t;
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-09-24 01:39:03 +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: {
|
2007-09-24 01:39:03 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +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
|
|
|
if (s == Thread::ZombieState) {
|
2007-09-24 01:39:03 +00:00
|
|
|
assert(t, t->m->liveCount > 0);
|
|
|
|
-- t->m->liveCount;
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
t->state = s;
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->stateLock->notifyAll(t->systemThread);
|
2007-07-06 23:50:26 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case Thread::ActiveState: {
|
|
|
|
switch (t->state) {
|
|
|
|
case Thread::ExclusiveState: {
|
2007-09-24 01:39:03 +00:00
|
|
|
assert(t, t->m->exclusive == t);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
|
|
|
t->state = s;
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->exclusive = 0;
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->stateLock->notifyAll(t->systemThread);
|
2007-07-06 23:50:26 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case Thread::NoState:
|
|
|
|
case Thread::IdleState: {
|
2007-09-24 01:39:03 +00:00
|
|
|
while (t->m->exclusive) {
|
|
|
|
t->m->stateLock->wait(t->systemThread, 0);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
++ t->m->activeCount;
|
2007-07-06 23:50:26 +00:00
|
|
|
if (t->state == Thread::NoState) {
|
2007-09-24 01:39:03 +00:00
|
|
|
++ 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: {
|
2007-09-24 01:39:03 +00:00
|
|
|
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);
|
|
|
|
}
|
2007-07-18 01:33:00 +00:00
|
|
|
|
2007-09-24 01:39:03 +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;
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
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)
|
|
|
|
{
|
2007-07-07 18:09:16 +00:00
|
|
|
if (sizeInBytes > Thread::HeapSizeInBytes and t->large == 0) {
|
2007-07-06 23:50:26 +00:00
|
|
|
return allocateLarge(t, sizeInBytes);
|
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
ACQUIRE_RAW(t, t->m->stateLock);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-09-24 01:39:03 +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
|
|
|
}
|
|
|
|
|
2007-07-26 00:48:28 +00:00
|
|
|
if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
2007-07-06 23:50:26 +00:00
|
|
|
>= Thread::HeapSizeInWords)
|
|
|
|
{
|
2007-08-22 14:50:29 +00:00
|
|
|
t->heap = 0;
|
2007-09-24 01:39:03 +00:00
|
|
|
if (t->large == 0 and t->m->heapPoolIndex < Machine::HeapPoolSize) {
|
2007-09-07 00:21:52 +00:00
|
|
|
t->heap = static_cast<uintptr_t*>
|
2007-09-24 01:39:03 +00:00
|
|
|
(t->m->system->tryAllocate(Thread::HeapSizeInBytes));
|
2007-08-22 14:50:29 +00:00
|
|
|
if (t->heap) {
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->heapPool[t->m->heapPoolIndex++] = t->heap;
|
2007-08-23 02:24:25 +00:00
|
|
|
t->heapOffset += t->heapIndex;
|
|
|
|
t->heapIndex = 0;
|
2007-08-22 14:50:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (t->heap == 0) {
|
|
|
|
ENTER(t, Thread::ExclusiveState);
|
|
|
|
collect(t, Heap::MinorCollection);
|
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (sizeInBytes > Thread::HeapSizeInBytes) {
|
|
|
|
return allocateLarge(t, sizeInBytes);
|
|
|
|
} else {
|
|
|
|
return allocateSmall(t, sizeInBytes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeByteArray(Thread* t, const char* format, ...)
|
|
|
|
{
|
|
|
|
va_list a;
|
|
|
|
va_start(a, format);
|
|
|
|
object s = ::makeByteArray(t, format, a);
|
|
|
|
va_end(a);
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeString(Thread* t, const char* format, ...)
|
|
|
|
{
|
|
|
|
va_list a;
|
|
|
|
va_start(a, format);
|
|
|
|
object s = ::makeByteArray(t, format, a);
|
|
|
|
va_end(a);
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2007-07-08 01:06:32 +00:00
|
|
|
void
|
|
|
|
stringChars(Thread* t, object string, char* chars)
|
|
|
|
{
|
|
|
|
object data = stringData(t, string);
|
|
|
|
if (objectClass(t, data)
|
2007-09-24 01:39:03 +00:00
|
|
|
== arrayBody(t, t->m->types, Machine::ByteArrayType))
|
2007-07-08 01:06:32 +00:00
|
|
|
{
|
|
|
|
memcpy(chars,
|
|
|
|
&byteArrayBody(t, data, stringOffset(t, string)),
|
|
|
|
stringLength(t, string));
|
|
|
|
} else {
|
|
|
|
for (int i = 0; i < stringLength(t, string); ++i) {
|
|
|
|
chars[i] = charArrayBody(t, data, stringOffset(t, string) + i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
chars[stringLength(t, string)] = 0;
|
|
|
|
}
|
|
|
|
|
2007-07-24 01:44:20 +00:00
|
|
|
bool
|
|
|
|
isAssignableFrom(Thread* t, object a, object b)
|
|
|
|
{
|
2007-08-20 02:57:32 +00:00
|
|
|
if (a == b) return true;
|
|
|
|
|
2007-07-24 01:44:20 +00:00
|
|
|
if (classFlags(t, a) & ACC_INTERFACE) {
|
|
|
|
for (; b; b = classSuper(t, b)) {
|
|
|
|
object itable = classInterfaceTable(t, b);
|
2007-08-22 04:03:03 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
object
|
|
|
|
hashMapFindNode(Thread* t, object map, object key,
|
|
|
|
uint32_t (*hash)(Thread*, object),
|
|
|
|
bool (*equal)(Thread*, object, object))
|
|
|
|
{
|
2007-07-29 18:52:08 +00:00
|
|
|
bool weak = objectClass(t, map)
|
2007-09-24 01:39:03 +00:00
|
|
|
== arrayBody(t, t->m->types, Machine::WeakHashMapType);
|
2007-07-29 18:52:08 +00:00
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
object array = hashMapArray(t, map);
|
|
|
|
if (array) {
|
|
|
|
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
|
2007-07-11 04:19:26 +00:00
|
|
|
for (object n = arrayBody(t, array, index); n; n = tripleThird(t, n)) {
|
2007-07-14 17:31:01 +00:00
|
|
|
object k = tripleFirst(t, n);
|
|
|
|
if (weak) {
|
|
|
|
k = jreferenceTarget(t, k);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (equal(t, key, k)) {
|
2007-07-06 23:50:26 +00:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object),
|
|
|
|
unsigned size)
|
|
|
|
{
|
|
|
|
PROTECT(t, map);
|
|
|
|
|
2007-07-11 04:19:26 +00:00
|
|
|
object newArray = 0;
|
|
|
|
|
|
|
|
if (size) {
|
|
|
|
object oldArray = hashMapArray(t, map);
|
|
|
|
PROTECT(t, oldArray);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-07-11 04:19:26 +00:00
|
|
|
unsigned newLength = nextPowerOfTwo(size);
|
2007-07-21 20:44:39 +00:00
|
|
|
if (oldArray and arrayLength(t, oldArray) == newLength) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-07-11 04:19:26 +00:00
|
|
|
newArray = makeArray(t, newLength, true);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-07-11 04:19:26 +00:00
|
|
|
if (oldArray) {
|
2007-07-29 18:52:08 +00:00
|
|
|
bool weak = objectClass(t, map)
|
2007-09-24 01:39:03 +00:00
|
|
|
== arrayBody(t, t->m->types, Machine::WeakHashMapType);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-07-11 04:19:26 +00:00
|
|
|
for (unsigned i = 0; i < arrayLength(t, oldArray); ++i) {
|
|
|
|
object next;
|
|
|
|
for (object p = arrayBody(t, oldArray, i); p; p = next) {
|
|
|
|
next = tripleThird(t, p);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
object k = tripleFirst(t, p);
|
|
|
|
if (weak) {
|
|
|
|
k = jreferenceTarget(t, k);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned index = hash(t, k) & (newLength - 1);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, p, TripleThird, arrayBody(t, newArray, index));
|
|
|
|
set(t, newArray, ArrayBody + (index * BytesPerWord), p);
|
2007-07-11 04:19:26 +00:00
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, map, HashMapArray, newArray);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-07-14 17:31:01 +00:00
|
|
|
hashMapInsert(Thread* t, object map, object key, object value,
|
2007-07-11 04:19:26 +00:00
|
|
|
uint32_t (*hash)(Thread*, object))
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
2007-07-29 18:52:08 +00:00
|
|
|
bool weak = objectClass(t, map)
|
2007-09-24 01:39:03 +00:00
|
|
|
== arrayBody(t, t->m->types, Machine::WeakHashMapType);
|
2007-07-29 18:52:08 +00:00
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
object array = hashMapArray(t, map);
|
|
|
|
PROTECT(t, array);
|
|
|
|
|
|
|
|
++ hashMapSize(t, map);
|
|
|
|
|
|
|
|
if (array == 0 or hashMapSize(t, map) >= arrayLength(t, array) * 2) {
|
|
|
|
PROTECT(t, map);
|
|
|
|
PROTECT(t, key);
|
|
|
|
PROTECT(t, value);
|
|
|
|
|
|
|
|
hashMapResize(t, map, hash, array ? arrayLength(t, array) * 2 : 16);
|
|
|
|
array = hashMapArray(t, map);
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
if (weak) {
|
2007-07-19 23:45:44 +00:00
|
|
|
PROTECT(t, key);
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, value);
|
2007-07-19 23:45:44 +00:00
|
|
|
|
2007-08-14 02:35:49 +00:00
|
|
|
object r = makeWeakReference(t, 0, 0, 0, 0);
|
|
|
|
jreferenceTarget(t, r) = key;
|
2007-09-24 01:39:03 +00:00
|
|
|
jreferenceNext(t, r) = t->m->weakReferences;
|
|
|
|
key = t->m->weakReferences = r;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2007-07-19 23:45:44 +00:00
|
|
|
object n = makeTriple(t, key, value, arrayBody(t, array, index));
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, array, ArrayBody + (index * BytesPerWord), n);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
2007-07-14 17:31:01 +00:00
|
|
|
hashMapRemove(Thread* t, object map, object key,
|
|
|
|
uint32_t (*hash)(Thread*, object),
|
|
|
|
bool (*equal)(Thread*, object, object))
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
2007-07-29 18:52:08 +00:00
|
|
|
bool weak = objectClass(t, map)
|
2007-09-24 01:39:03 +00:00
|
|
|
== arrayBody(t, t->m->types, Machine::WeakHashMapType);
|
2007-07-29 18:52:08 +00:00
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
object array = hashMapArray(t, map);
|
|
|
|
object o = 0;
|
|
|
|
if (array) {
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
|
2007-10-22 17:22:30 +00:00
|
|
|
object p = 0;
|
|
|
|
for (object n = arrayBody(t, array, index); n;) {
|
|
|
|
object k = tripleFirst(t, n);
|
2007-07-14 17:31:01 +00:00
|
|
|
if (weak) {
|
|
|
|
k = jreferenceTarget(t, k);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (equal(t, key, k)) {
|
2007-10-22 17:22:30 +00:00
|
|
|
o = tripleSecond(t, n);
|
|
|
|
if (p) {
|
|
|
|
set(t, p, TripleThird, tripleThird(t, n));
|
|
|
|
} else {
|
|
|
|
set(t, array, ArrayBody + (index * BytesPerWord),
|
|
|
|
tripleThird(t, n));
|
|
|
|
}
|
2007-07-11 04:19:26 +00:00
|
|
|
-- hashMapSize(t, map);
|
2007-07-21 20:44:39 +00:00
|
|
|
break;
|
2007-07-11 04:19:26 +00:00
|
|
|
} else {
|
2007-10-22 17:22:30 +00:00
|
|
|
p = n;
|
|
|
|
n = tripleThird(t, n);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-11 04:19:26 +00:00
|
|
|
if (hashMapSize(t, map) <= arrayLength(t, array) / 3) {
|
2007-07-19 23:45:44 +00:00
|
|
|
PROTECT(t, o);
|
2007-07-11 04:19:26 +00:00
|
|
|
hashMapResize(t, map, hash, arrayLength(t, array) / 2);
|
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
hashMapIterator(Thread* t, object map)
|
|
|
|
{
|
|
|
|
object array = hashMapArray(t, map);
|
|
|
|
if (array) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, array); ++i) {
|
|
|
|
if (arrayBody(t, array, i)) {
|
|
|
|
return makeHashMapIterator(t, map, arrayBody(t, array, i), i + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
hashMapIteratorNext(Thread* t, object it)
|
|
|
|
{
|
|
|
|
object map = hashMapIteratorMap(t, it);
|
|
|
|
object node = hashMapIteratorNode(t, it);
|
|
|
|
unsigned index = hashMapIteratorIndex(t, it);
|
|
|
|
|
|
|
|
if (tripleThird(t, node)) {
|
2007-08-14 00:37:00 +00:00
|
|
|
return makeHashMapIterator(t, map, tripleThird(t, node), index);
|
2007-07-06 23:50:26 +00:00
|
|
|
} else {
|
|
|
|
object array = hashMapArray(t, map);
|
|
|
|
for (unsigned i = index; i < arrayLength(t, array); ++i) {
|
|
|
|
if (arrayBody(t, array, i)) {
|
|
|
|
return makeHashMapIterator(t, map, arrayBody(t, array, i), i + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
listAppend(Thread* t, object list, object value)
|
|
|
|
{
|
|
|
|
PROTECT(t, list);
|
|
|
|
|
|
|
|
++ listSize(t, list);
|
|
|
|
|
|
|
|
object p = makePair(t, value, 0);
|
|
|
|
if (listFront(t, list)) {
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, listRear(t, list), PairSecond, p);
|
2007-07-06 23:50:26 +00:00
|
|
|
} else {
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, list, ListFront, p);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, list, ListRear, p);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
2007-09-07 00:21:52 +00:00
|
|
|
object
|
|
|
|
vectorAppend(Thread* t, object vector, object value)
|
|
|
|
{
|
|
|
|
if (vectorLength(t, vector) == vectorSize(t, vector)) {
|
|
|
|
PROTECT(t, vector);
|
|
|
|
PROTECT(t, value);
|
|
|
|
|
|
|
|
object newVector = makeVector
|
|
|
|
(t, vectorSize(t, vector), max(16, vectorSize(t, vector) * 2), false);
|
|
|
|
|
|
|
|
if (vectorSize(t, vector)) {
|
|
|
|
memcpy(&vectorBody(t, newVector, 0),
|
|
|
|
&vectorBody(t, vector, 0),
|
|
|
|
vectorSize(t, vector) * BytesPerWord);
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&vectorBody(t, newVector, vectorSize(t, vector) + 1),
|
|
|
|
0,
|
|
|
|
(vectorLength(t, newVector) - vectorSize(t, vector) - 1)
|
|
|
|
* BytesPerWord);
|
|
|
|
|
|
|
|
vector = newVector;
|
|
|
|
}
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, vector, VectorBody + (vectorSize(t, vector) * BytesPerWord), value);
|
|
|
|
++ vectorSize(t, vector);
|
2007-09-07 00:21:52 +00:00
|
|
|
return vector;
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned
|
|
|
|
fieldCode(Thread* t, unsigned javaCode)
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
2007-07-14 17:31:01 +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
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-07-14 17:31:01 +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
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned
|
|
|
|
primitiveSize(Thread* t, unsigned code)
|
2007-07-11 04:19:26 +00:00
|
|
|
{
|
2007-07-14 17:31:01 +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
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
}
|
2007-07-11 04:19:26 +00:00
|
|
|
|
2007-07-30 23:19:05 +00:00
|
|
|
object
|
2007-08-10 23:45:47 +00:00
|
|
|
findLoadedClass(Thread* t, object spec)
|
2007-07-30 23:19:05 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, spec);
|
2007-09-24 01:39:03 +00:00
|
|
|
ACQUIRE(t, t->m->classLock);
|
2007-07-30 23:19:05 +00:00
|
|
|
|
2007-09-24 01:39:03 +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 handleEOS() {
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Thread* t;
|
|
|
|
} client(t);
|
|
|
|
|
|
|
|
Stream s(&client, data, size);
|
|
|
|
|
|
|
|
uint32_t magic = s.read4();
|
2007-08-19 19:45:51 +00:00
|
|
|
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
|
|
|
|
arrayBody(t, pool, name - 1),
|
|
|
|
0, // super
|
|
|
|
0, // interfaces
|
|
|
|
0, // vtable
|
|
|
|
0, // fields
|
|
|
|
0, // methods
|
|
|
|
0, // static table
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->loader);
|
2007-07-30 23:19:05 +00:00
|
|
|
PROTECT(t, class_);
|
|
|
|
|
|
|
|
unsigned super = s.read2();
|
|
|
|
if (super) {
|
|
|
|
object sc = resolveClass(t, arrayBody(t, pool, super - 1));
|
|
|
|
if (UNLIKELY(t->exception)) return 0;
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
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;
|
|
|
|
|
|
|
|
return class_;
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
object
|
|
|
|
resolveClass(Thread* t, object spec)
|
|
|
|
{
|
|
|
|
PROTECT(t, spec);
|
2007-09-24 01:39:03 +00:00
|
|
|
ACQUIRE(t, t->m->classLock);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
object class_ = hashMapFind(t, systemClassLoaderMap(t, t->m->loader),
|
2007-07-30 23:19:05 +00:00
|
|
|
spec, byteArrayHash, byteArrayEqual);
|
2007-07-14 17:31:01 +00:00
|
|
|
if (class_ == 0) {
|
|
|
|
if (byteArrayBody(t, spec, 0) == '[') {
|
|
|
|
class_ = hashMapFind
|
2007-09-24 01:39:03 +00:00
|
|
|
(t, t->m->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-10-11 22:43:03 +00:00
|
|
|
if (class_) {
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, class_, ClassVirtualTable,
|
2007-10-11 22:43:03 +00:00
|
|
|
classVirtualTable
|
|
|
|
(t, arrayBody(t, t->m->types, Machine::JobjectType)));
|
|
|
|
} else {
|
2007-07-14 17:31:01 +00:00
|
|
|
class_ = makeArrayClass(t, spec);
|
|
|
|
}
|
|
|
|
} else {
|
2007-08-10 23:45:47 +00:00
|
|
|
char file[byteArrayLength(t, spec) + 6];
|
|
|
|
memcpy(file, &byteArrayBody(t, spec, 0), byteArrayLength(t, spec) - 1);
|
|
|
|
memcpy(file + byteArrayLength(t, spec) - 1, ".class", 7);
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
System::Region* region = t->m->finder->find(file);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
if (region) {
|
2007-07-14 17:31:01 +00:00
|
|
|
if (Verbose) {
|
2007-07-24 03:31:28 +00:00
|
|
|
fprintf(stderr, "parsing %s\n", &byteArrayBody(t, spec, 0));
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// parse class file
|
2007-09-17 00:13:36 +00:00
|
|
|
class_ = parseClass(t, region->start(), region->length());
|
|
|
|
region->dispose();
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-07-24 03:31:28 +00:00
|
|
|
if (LIKELY(t->exception == 0)) {
|
|
|
|
if (Verbose) {
|
|
|
|
fprintf(stderr, "done parsing %s\n", &byteArrayBody(t, spec, 0));
|
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-07-24 03:31:28 +00:00
|
|
|
object bootstrapClass = hashMapFind
|
2007-09-24 01:39:03 +00:00
|
|
|
(t, t->m->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-07-24 03:31:28 +00:00
|
|
|
if (bootstrapClass) {
|
|
|
|
PROTECT(t, bootstrapClass);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-07-24 03:31:28 +00:00
|
|
|
updateBootstrapClass(t, bootstrapClass, class_);
|
|
|
|
class_ = bootstrapClass;
|
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (class_) {
|
2007-07-16 23:58:37 +00:00
|
|
|
PROTECT(t, class_);
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
hashMapInsert(t, systemClassLoaderMap(t, t->m->loader),
|
2007-07-30 23:19:05 +00:00
|
|
|
spec, class_, byteArrayHash);
|
2007-07-14 17:31:01 +00:00
|
|
|
} 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
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
return class_;
|
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
object
|
|
|
|
resolveObjectArrayClass(Thread* t, object elementSpec)
|
|
|
|
{
|
|
|
|
PROTECT(t, elementSpec);
|
|
|
|
|
|
|
|
object spec;
|
|
|
|
if (byteArrayBody(t, elementSpec, 0) == '[') {
|
|
|
|
spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 1, false);
|
2007-09-13 00:21:37 +00:00
|
|
|
byteArrayBody(t, spec, 0) = '[';
|
2007-07-14 17:31:01 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-09-07 00:21:52 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
void
|
|
|
|
addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object))
|
|
|
|
{
|
|
|
|
PROTECT(t, target);
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
ACQUIRE(t, t->m->referenceLock);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-10-22 20:56:27 +00:00
|
|
|
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;
|
2007-09-24 01:39:03 +00:00
|
|
|
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*
|
|
|
|
objectMonitor(Thread* t, object o)
|
|
|
|
{
|
2007-09-24 01:39:03 +00:00
|
|
|
object p = hashMapFind(t, t->m->monitorMap, o, objectHash, objectEqual);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
|
|
|
if (p) {
|
2007-07-10 23:34:53 +00:00
|
|
|
if (DebugMonitors) {
|
2007-07-11 04:19:26 +00:00
|
|
|
fprintf(stderr, "found monitor %p for object %x\n",
|
2007-07-10 23:34:53 +00:00
|
|
|
static_cast<System::Monitor*>(pointerValue(t, p)),
|
|
|
|
objectHash(t, o));
|
|
|
|
}
|
2007-07-10 03:04:49 +00:00
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
return static_cast<System::Monitor*>(pointerValue(t, p));
|
|
|
|
} else {
|
|
|
|
PROTECT(t, o);
|
|
|
|
|
|
|
|
ENTER(t, Thread::ExclusiveState);
|
|
|
|
|
|
|
|
System::Monitor* m;
|
2007-09-24 01:39:03 +00:00
|
|
|
System::Status s = t->m->system->make(&m);
|
|
|
|
expect(t, t->m->system->success(s));
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-07-10 23:34:53 +00:00
|
|
|
if (DebugMonitors) {
|
2007-07-11 04:19:26 +00:00
|
|
|
fprintf(stderr, "made monitor %p for object %x\n",
|
2007-07-10 23:34:53 +00:00
|
|
|
m,
|
|
|
|
objectHash(t, o));
|
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
p = makePointer(t, m);
|
2007-09-24 01:39:03 +00:00
|
|
|
hashMapInsert(t, t->m->monitorMap, o, p, objectHash);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
|
|
|
addFinalizer(t, o, removeMonitor);
|
|
|
|
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-29 00:02:32 +00:00
|
|
|
object
|
|
|
|
intern(Thread* t, object s)
|
|
|
|
{
|
2007-07-29 18:52:08 +00:00
|
|
|
PROTECT(t, s);
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
ACQUIRE(t, t->m->referenceLock);
|
2007-07-29 00:02:32 +00:00
|
|
|
|
2007-09-24 01:39:03 +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 {
|
2007-09-24 01:39:03 +00:00
|
|
|
hashMapInsert(t, t->m->stringMap, s, 0, stringHash);
|
2007-07-29 00:02:32 +00:00
|
|
|
addFinalizer(t, s, removeString);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-16 01:03:02 +00:00
|
|
|
void
|
|
|
|
collect(Thread* t, Heap::CollectionType type)
|
|
|
|
{
|
2007-09-24 01:39:03 +00:00
|
|
|
Machine* m = t->m;
|
2007-07-16 01:03:02 +00:00
|
|
|
|
|
|
|
class Client: public Heap::Client {
|
|
|
|
public:
|
|
|
|
Client(Machine* m): m(m) { }
|
|
|
|
|
|
|
|
virtual void visitRoots(Heap::Visitor* v) {
|
2007-07-30 23:19:05 +00:00
|
|
|
v->visit(&(m->loader));
|
2007-07-16 01:03:02 +00:00
|
|
|
v->visit(&(m->bootstrapClassMap));
|
|
|
|
v->visit(&(m->monitorMap));
|
2007-07-29 00:02:32 +00:00
|
|
|
v->visit(&(m->stringMap));
|
2007-07-16 01:03:02 +00:00
|
|
|
v->visit(&(m->types));
|
2007-09-07 23:20:21 +00:00
|
|
|
v->visit(&(m->jniInterfaceTable));
|
|
|
|
|
|
|
|
for (Reference* r = m->jniReferences; r; r = r->next) {
|
|
|
|
v->visit(&(r->target));
|
|
|
|
}
|
2007-07-16 01:03:02 +00:00
|
|
|
|
|
|
|
for (Thread* t = m->rootThread; t; t = t->peer) {
|
|
|
|
::visitRoots(t, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
postVisit(m->rootThread, v);
|
|
|
|
}
|
|
|
|
|
2007-09-07 00:21:52 +00:00
|
|
|
virtual unsigned sizeInWords(void* p) {
|
2007-07-16 01:03:02 +00:00
|
|
|
Thread* t = m->rootThread;
|
|
|
|
|
2007-09-07 00:21:52 +00:00
|
|
|
object o = static_cast<object>(m->heap->follow(mask(p)));
|
2007-07-16 01:03:02 +00:00
|
|
|
|
|
|
|
return extendedSize
|
2007-09-07 00:21:52 +00:00
|
|
|
(t, o, baseSize(t, o, static_cast<object>
|
|
|
|
(m->heap->follow(objectClass(t, o)))));
|
2007-07-16 01:03:02 +00:00
|
|
|
}
|
|
|
|
|
2007-09-07 00:21:52 +00:00
|
|
|
virtual unsigned copiedSizeInWords(void* p) {
|
2007-07-16 01:03:02 +00:00
|
|
|
Thread* t = m->rootThread;
|
|
|
|
|
2007-09-07 00:21:52 +00:00
|
|
|
object o = static_cast<object>(m->heap->follow(mask(p)));
|
2007-07-16 01:03:02 +00:00
|
|
|
|
2007-09-07 00:21:52 +00:00
|
|
|
unsigned n = baseSize(t, o, static_cast<object>
|
|
|
|
(m->heap->follow(objectClass(t, o))));
|
2007-07-16 01:03:02 +00:00
|
|
|
|
|
|
|
if (objectExtended(t, o) or hashTaken(t, o)) {
|
|
|
|
++ n;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2007-09-07 00:21:52 +00:00
|
|
|
virtual void copy(void* srcp, void* dstp) {
|
2007-07-16 01:03:02 +00:00
|
|
|
Thread* t = m->rootThread;
|
|
|
|
|
2007-09-07 00:21:52 +00:00
|
|
|
object src = static_cast<object>(m->heap->follow(mask(srcp)));
|
|
|
|
object class_ = static_cast<object>
|
|
|
|
(m->heap->follow(objectClass(t, src)));
|
|
|
|
|
|
|
|
unsigned base = baseSize(t, src, class_);
|
|
|
|
unsigned n = extendedSize(t, src, base);
|
2007-07-16 01:03:02 +00:00
|
|
|
|
2007-09-07 00:21:52 +00:00
|
|
|
object dst = static_cast<object>(dstp);
|
2007-07-16 01:03:02 +00:00
|
|
|
|
2007-09-07 00:21:52 +00:00
|
|
|
memcpy(dst, src, n * BytesPerWord);
|
2007-07-16 01:03:02 +00:00
|
|
|
|
2007-09-07 00:21:52 +00:00
|
|
|
if (hashTaken(t, src)) {
|
2007-07-16 01:03:02 +00:00
|
|
|
cast<uintptr_t>(dst, 0) &= PointerMask;
|
|
|
|
cast<uintptr_t>(dst, 0) |= ExtendedMark;
|
2007-09-07 00:21:52 +00:00
|
|
|
extendedWord(t, dst, base) = takeHash(t, src);
|
2007-07-16 01:03:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void walk(void* p, Heap::Walker* w) {
|
|
|
|
Thread* t = m->rootThread;
|
|
|
|
|
2007-09-07 00:21:52 +00:00
|
|
|
object o = static_cast<object>(m->heap->follow(mask(p)));
|
|
|
|
object class_ = static_cast<object>(m->heap->follow(objectClass(t, o)));
|
|
|
|
object objectMask = static_cast<object>
|
|
|
|
(m->heap->follow(classObjectMask(t, class_)));
|
2007-07-16 01:03:02 +00:00
|
|
|
|
|
|
|
if (objectMask) {
|
|
|
|
// fprintf(stderr, "p: %p; class: %p; mask: %p; mask length: %d\n",
|
|
|
|
// p, class_, objectMask, intArrayLength(t, objectMask));
|
|
|
|
|
|
|
|
unsigned fixedSize = classFixedSize(t, class_);
|
|
|
|
unsigned arrayElementSize = classArrayElementSize(t, class_);
|
|
|
|
unsigned arrayLength
|
|
|
|
= (arrayElementSize ?
|
|
|
|
cast<uintptr_t>(p, fixedSize - BytesPerWord) : 0);
|
|
|
|
|
|
|
|
int mask[intArrayLength(t, objectMask)];
|
|
|
|
memcpy(mask, &intArrayBody(t, objectMask, 0),
|
|
|
|
intArrayLength(t, objectMask) * 4);
|
|
|
|
|
|
|
|
// fprintf
|
|
|
|
// (stderr,
|
|
|
|
// "fixed size: %d; array length: %d; element size: %d; mask: %x\n",
|
|
|
|
// fixedSize, arrayLength, arrayElementSize, mask[0]);
|
|
|
|
|
2007-07-26 00:48:28 +00:00
|
|
|
unsigned fixedSizeInWords = ceiling(fixedSize, BytesPerWord);
|
2007-07-16 01:03:02 +00:00
|
|
|
unsigned arrayElementSizeInWords
|
2007-07-26 00:48:28 +00:00
|
|
|
= ceiling(arrayElementSize, BytesPerWord);
|
2007-07-16 01:03:02 +00:00
|
|
|
|
|
|
|
for (unsigned i = 0; i < fixedSizeInWords; ++i) {
|
2007-09-13 22:45:09 +00:00
|
|
|
if (mask[i / 32] & (static_cast<uintptr_t>(1) << (i % 32))) {
|
2007-07-16 01:03:02 +00:00
|
|
|
if (not w->visit(i)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool arrayObjectElements = false;
|
|
|
|
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
|
|
|
|
unsigned k = fixedSizeInWords + j;
|
2007-09-13 22:45:09 +00:00
|
|
|
if (mask[k / 32] & (static_cast<uintptr_t>(1) << (k % 32))) {
|
2007-07-16 01:03:02 +00:00
|
|
|
arrayObjectElements = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arrayObjectElements) {
|
|
|
|
for (unsigned i = 0; i < arrayLength; ++i) {
|
|
|
|
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
|
|
|
|
unsigned k = fixedSizeInWords + j;
|
2007-09-13 22:45:09 +00:00
|
|
|
if (mask[k / 32] & (static_cast<uintptr_t>(1) << (k % 32))) {
|
2007-07-16 01:03:02 +00:00
|
|
|
if (not w->visit
|
|
|
|
(fixedSizeInWords + (i * arrayElementSizeInWords) + j))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
w->visit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Machine* m;
|
|
|
|
} it(m);
|
|
|
|
|
|
|
|
m->unsafe = true;
|
2007-08-18 21:24:29 +00:00
|
|
|
m->heap->collect(type, &it, footprint(m->rootThread));
|
2007-07-16 01:03:02 +00:00
|
|
|
m->unsafe = false;
|
|
|
|
|
|
|
|
postCollect(m->rootThread);
|
|
|
|
|
|
|
|
for (object f = m->finalizeQueue; f; f = finalizerNext(t, f)) {
|
2007-10-22 20:56:27 +00:00
|
|
|
void (*function)(Thread*, object);
|
|
|
|
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
|
|
|
|
function(t, finalizerTarget(t, f));
|
2007-07-16 01:03:02 +00:00
|
|
|
}
|
|
|
|
m->finalizeQueue = 0;
|
|
|
|
|
|
|
|
killZombies(t, m->rootThread);
|
2007-08-22 14:50:29 +00:00
|
|
|
|
|
|
|
for (unsigned i = 0; i < m->heapPoolIndex; ++i) {
|
|
|
|
m->system->free(m->heapPool[i]);
|
|
|
|
}
|
|
|
|
m->heapPoolIndex = 0;
|
2007-07-16 01:03:02 +00:00
|
|
|
}
|
|
|
|
|
2007-07-24 03:16:59 +00:00
|
|
|
void
|
|
|
|
printTrace(Thread* t, object exception)
|
|
|
|
{
|
2007-10-12 20:54:37 +00:00
|
|
|
if (exception == 0) {
|
2007-10-13 00:22:52 +00:00
|
|
|
exception = makeNullPointerException(t, 0, makeTrace(t), 0);
|
2007-10-12 20:54:37 +00:00
|
|
|
}
|
2007-10-13 00:22:52 +00:00
|
|
|
|
2007-07-24 03:16:59 +00:00
|
|
|
for (object e = exception; e; e = throwableCauseUnsafe(t, e)) {
|
|
|
|
if (e != exception) {
|
|
|
|
fprintf(stderr, "caused by: ");
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "%s", &byteArrayBody
|
|
|
|
(t, className(t, objectClass(t, e)), 0));
|
|
|
|
|
|
|
|
if (throwableMessageUnsafe(t, e)) {
|
|
|
|
object m = throwableMessageUnsafe(t, e);
|
|
|
|
char message[stringLength(t, m) + 1];
|
|
|
|
stringChars(t, m, message);
|
|
|
|
fprintf(stderr, ": %s\n", message);
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
object trace = throwableTraceUnsafe(t, e);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
object
|
2007-09-24 13:46:48 +00:00
|
|
|
makeTrace(Thread* t, uintptr_t start)
|
2007-09-24 01:39:03 +00:00
|
|
|
{
|
2007-09-24 13:46:48 +00:00
|
|
|
Processor* p = t->m->processor;
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
unsigned count = 0;
|
2007-09-24 13:46:48 +00:00
|
|
|
for (uintptr_t frame = start;
|
|
|
|
p->frameValid(t, frame);
|
|
|
|
frame = p->frameNext(t, frame))
|
|
|
|
{
|
2007-09-24 01:39:03 +00:00
|
|
|
++ count;
|
|
|
|
}
|
|
|
|
|
|
|
|
object trace = makeArray(t, count, true);
|
|
|
|
PROTECT(t, trace);
|
|
|
|
|
|
|
|
unsigned index = 0;
|
2007-09-24 13:46:48 +00:00
|
|
|
for (uintptr_t frame = start;
|
|
|
|
p->frameValid(t, frame);
|
|
|
|
frame = p->frameNext(t, frame))
|
|
|
|
{
|
|
|
|
object e = makeTraceElement
|
|
|
|
(t, p->frameMethod(t, frame), p->frameIp(t, frame));
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, trace, ArrayBody + (index * BytesPerWord), e);
|
|
|
|
++ index;
|
2007-09-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return trace;
|
|
|
|
}
|
|
|
|
|
2007-07-10 01:43:43 +00:00
|
|
|
void
|
|
|
|
noop()
|
|
|
|
{ }
|
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
#include "type-constructors.cpp"
|
|
|
|
|
|
|
|
} // namespace vm
|