2011-07-13 14:25:21 +00:00
|
|
|
/* Copyright (c) 2008-2011, Avian Contributors
|
2008-02-19 18:06:52 +00:00
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software
|
|
|
|
for any purpose with or without fee is hereby granted, provided
|
|
|
|
that the above copyright notice and this permission notice appear
|
|
|
|
in all copies.
|
|
|
|
|
|
|
|
There is NO WARRANTY for this software. See license.txt for
|
|
|
|
details. */
|
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
#include "jnienv.h"
|
|
|
|
#include "machine.h"
|
2007-11-26 23:15:53 +00:00
|
|
|
#include "util.h"
|
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"
|
2009-11-28 22:01:54 +00:00
|
|
|
#include "arch.h"
|
2007-07-06 23:50:26 +00:00
|
|
|
|
|
|
|
using namespace vm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2009-08-14 14:52:31 +00:00
|
|
|
const unsigned NoByte = 0xFFFF;
|
|
|
|
|
2009-11-28 22:01:54 +00:00
|
|
|
#ifdef USE_ATOMIC_OPERATIONS
|
|
|
|
void
|
2009-11-29 16:08:07 +00:00
|
|
|
atomicIncrement(uint32_t* p, int v)
|
2009-11-28 22:01:54 +00:00
|
|
|
{
|
2009-11-29 16:08:07 +00:00
|
|
|
for (uint32_t old = *p;
|
|
|
|
not atomicCompareAndSwap32(p, old, old + v);
|
|
|
|
old = *p)
|
|
|
|
{ }
|
2009-11-28 22:01:54 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-07-07 18:09:16 +00:00
|
|
|
bool
|
|
|
|
find(Thread* t, Thread* o)
|
|
|
|
{
|
2008-04-11 22:48:05 +00:00
|
|
|
return (t == o)
|
|
|
|
or (t->peer and find(t->peer, o))
|
|
|
|
or (t->child and find(t->child, o));
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
join(Thread* t, Thread* o)
|
|
|
|
{
|
|
|
|
if (t != o) {
|
2012-01-12 18:00:58 +00:00
|
|
|
// todo: There's potentially a leak here on systems where we must
|
|
|
|
// call join on a thread in order to clean up all resources
|
|
|
|
// associated with it. If a thread has already been zombified by
|
|
|
|
// the time we get here, acquireSystem will return false, which
|
|
|
|
// means we can't safely join it because the System::Thread may
|
|
|
|
// already have been disposed. In that case, the thread has
|
|
|
|
// already exited (or will soon), but the OS will never free all
|
|
|
|
// its resources because it doesn't know we're completely done
|
|
|
|
// with it.
|
2010-11-16 17:50:19 +00:00
|
|
|
if (acquireSystem(t, o)) {
|
2010-11-09 22:46:16 +00:00
|
|
|
o->systemThread->join();
|
2010-11-16 17:50:19 +00:00
|
|
|
releaseSystem(t, o);
|
2010-11-09 22:46:16 +00:00
|
|
|
}
|
2007-07-18 01:33:00 +00:00
|
|
|
o->state = Thread::JoinedState;
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-27 22:23:00 +00:00
|
|
|
unsigned
|
|
|
|
count(Thread* t, Thread* o)
|
|
|
|
{
|
|
|
|
unsigned c = 0;
|
|
|
|
|
|
|
|
if (t != o) ++ c;
|
2008-04-11 22:48:05 +00:00
|
|
|
if (t->peer) c += count(t->peer, o);
|
2007-11-27 22:23:00 +00:00
|
|
|
if (t->child) c += count(t->child, o);
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
Thread**
|
|
|
|
fill(Thread* t, Thread* o, Thread** array)
|
|
|
|
{
|
|
|
|
if (t != o) *(array++) = t;
|
2008-07-21 20:41:29 +00:00
|
|
|
if (t->peer) array = fill(t->peer, o, array);
|
|
|
|
if (t->child) array = fill(t->child, o, array);
|
2007-11-27 22:23:00 +00:00
|
|
|
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
|
2007-07-07 18:09:16 +00:00
|
|
|
void
|
|
|
|
dispose(Thread* t, Thread* o, bool remove)
|
|
|
|
{
|
|
|
|
if (remove) {
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifndef NDEBUG
|
2007-11-27 22:23:00 +00:00
|
|
|
expect(t, find(t->m->rootThread, o));
|
|
|
|
|
|
|
|
unsigned c = count(t->m->rootThread, o);
|
2010-12-27 22:55:23 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, Thread*, threads, c);
|
2009-09-19 00:01:54 +00:00
|
|
|
fill(t->m->rootThread, o, RUNTIME_ARRAY_BODY(threads));
|
2009-08-27 00:26:44 +00:00
|
|
|
#endif
|
2007-11-27 22:23:00 +00:00
|
|
|
|
2007-07-07 18:09:16 +00:00
|
|
|
if (o->parent) {
|
2007-11-27 23:04:15 +00:00
|
|
|
Thread* previous = 0;
|
2007-11-27 22:23:00 +00:00
|
|
|
for (Thread* p = o->parent->child; p;) {
|
|
|
|
if (p == o) {
|
|
|
|
if (p == o->parent->child) {
|
|
|
|
o->parent->child = p->peer;
|
|
|
|
} else {
|
|
|
|
previous->peer = p->peer;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
previous = p;
|
|
|
|
p = p->peer;
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
2007-11-27 22:23:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (Thread* p = o->child; p;) {
|
|
|
|
Thread* next = p->peer;
|
|
|
|
p->peer = o->parent->child;
|
|
|
|
o->parent->child = p;
|
|
|
|
p->parent = o->parent;
|
|
|
|
p = next;
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
} else if (o->child) {
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->rootThread = o->child;
|
2007-11-27 22:23:00 +00:00
|
|
|
|
|
|
|
for (Thread* p = o->peer; p;) {
|
|
|
|
Thread* next = p->peer;
|
|
|
|
p->peer = t->m->rootThread;
|
|
|
|
t->m->rootThread = p;
|
|
|
|
p = next;
|
|
|
|
}
|
2007-07-07 18:09:16 +00:00
|
|
|
} else if (o->peer) {
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->rootThread = o->peer;
|
2007-07-07 18:09:16 +00:00
|
|
|
} else {
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
#ifndef NDEBUG
|
2007-11-27 22:23:00 +00:00
|
|
|
expect(t, not find(t->m->rootThread, o));
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < c; ++i) {
|
2009-09-19 00:01:54 +00:00
|
|
|
expect(t, find(t->m->rootThread, RUNTIME_ARRAY_BODY(threads)[i]));
|
2007-11-27 22:23:00 +00:00
|
|
|
}
|
2009-08-27 00:26:44 +00:00
|
|
|
#endif
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
o->dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
support multiple sequential VM instances with bootimage build
Until now, the bootimage build hasn't supported using the Java
invocation API to create a VM, destroy it, and create another in the
same process. Ideally, we would be able to create multiple VMs
simultaneously without any interference between them. In fact, Avian
is designed to support this for the most part, but there are a few
places we use global, mutable state which prevent this from working.
Most notably, the bootimage is modified in-place at runtime, so the
best we can do without extensive changes is to clean up the bootimage
when the VM is destroyed so it's ready for later instances. Hence
this commit.
Ultimately, we can move towards a fully reentrant VM by making the
bootimage immutable, but this will require some care to avoid
performance regressions. Another challenge is our Posix signal
handlers, which currently rely on a global handle to the VM, since you
can't, to my knowledge, pass a context pointer when registering a
signal handler. Thread local variables won't necessarily help, since
a thread might attatch to more than one VM at a time.
2011-11-10 20:10:53 +00:00
|
|
|
visitAll(Thread* m, Thread* o, void (*visit)(Thread*, Thread*))
|
2007-07-07 18:09:16 +00:00
|
|
|
{
|
|
|
|
for (Thread* p = o->child; p;) {
|
|
|
|
Thread* child = p;
|
|
|
|
p = p->peer;
|
support multiple sequential VM instances with bootimage build
Until now, the bootimage build hasn't supported using the Java
invocation API to create a VM, destroy it, and create another in the
same process. Ideally, we would be able to create multiple VMs
simultaneously without any interference between them. In fact, Avian
is designed to support this for the most part, but there are a few
places we use global, mutable state which prevent this from working.
Most notably, the bootimage is modified in-place at runtime, so the
best we can do without extensive changes is to clean up the bootimage
when the VM is destroyed so it's ready for later instances. Hence
this commit.
Ultimately, we can move towards a fully reentrant VM by making the
bootimage immutable, but this will require some care to avoid
performance regressions. Another challenge is our Posix signal
handlers, which currently rely on a global handle to the VM, since you
can't, to my knowledge, pass a context pointer when registering a
signal handler. Thread local variables won't necessarily help, since
a thread might attatch to more than one VM at a time.
2011-11-10 20:10:53 +00:00
|
|
|
visitAll(m, child, visit);
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
|
support multiple sequential VM instances with bootimage build
Until now, the bootimage build hasn't supported using the Java
invocation API to create a VM, destroy it, and create another in the
same process. Ideally, we would be able to create multiple VMs
simultaneously without any interference between them. In fact, Avian
is designed to support this for the most part, but there are a few
places we use global, mutable state which prevent this from working.
Most notably, the bootimage is modified in-place at runtime, so the
best we can do without extensive changes is to clean up the bootimage
when the VM is destroyed so it's ready for later instances. Hence
this commit.
Ultimately, we can move towards a fully reentrant VM by making the
bootimage immutable, but this will require some care to avoid
performance regressions. Another challenge is our Posix signal
handlers, which currently rely on a global handle to the VM, since you
can't, to my knowledge, pass a context pointer when registering a
signal handler. Thread local variables won't necessarily help, since
a thread might attatch to more than one VM at a time.
2011-11-10 20:10:53 +00:00
|
|
|
visit(m, o);
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
support multiple sequential VM instances with bootimage build
Until now, the bootimage build hasn't supported using the Java
invocation API to create a VM, destroy it, and create another in the
same process. Ideally, we would be able to create multiple VMs
simultaneously without any interference between them. In fact, Avian
is designed to support this for the most part, but there are a few
places we use global, mutable state which prevent this from working.
Most notably, the bootimage is modified in-place at runtime, so the
best we can do without extensive changes is to clean up the bootimage
when the VM is destroyed so it's ready for later instances. Hence
this commit.
Ultimately, we can move towards a fully reentrant VM by making the
bootimage immutable, but this will require some care to avoid
performance regressions. Another challenge is our Posix signal
handlers, which currently rely on a global handle to the VM, since you
can't, to my knowledge, pass a context pointer when registering a
signal handler. Thread local variables won't necessarily help, since
a thread might attatch to more than one VM at a time.
2011-11-10 20:10:53 +00:00
|
|
|
disposeNoRemove(Thread* m, Thread* o)
|
2007-07-07 18:09:16 +00:00
|
|
|
{
|
|
|
|
dispose(m, o, false);
|
|
|
|
}
|
|
|
|
|
support multiple sequential VM instances with bootimage build
Until now, the bootimage build hasn't supported using the Java
invocation API to create a VM, destroy it, and create another in the
same process. Ideally, we would be able to create multiple VMs
simultaneously without any interference between them. In fact, Avian
is designed to support this for the most part, but there are a few
places we use global, mutable state which prevent this from working.
Most notably, the bootimage is modified in-place at runtime, so the
best we can do without extensive changes is to clean up the bootimage
when the VM is destroyed so it's ready for later instances. Hence
this commit.
Ultimately, we can move towards a fully reentrant VM by making the
bootimage immutable, but this will require some care to avoid
performance regressions. Another challenge is our Posix signal
handlers, which currently rely on a global handle to the VM, since you
can't, to my knowledge, pass a context pointer when registering a
signal handler. Thread local variables won't necessarily help, since
a thread might attatch to more than one VM at a time.
2011-11-10 20:10:53 +00:00
|
|
|
void
|
|
|
|
interruptDaemon(Thread* m, Thread* o)
|
|
|
|
{
|
|
|
|
if (o->flags & Thread::DaemonFlag) {
|
|
|
|
interrupt(m, o);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-19 20:27:03 +00:00
|
|
|
void
|
|
|
|
turnOffTheLights(Thread* t)
|
|
|
|
{
|
|
|
|
expect(t, t->m->liveCount == 1);
|
|
|
|
|
support multiple sequential VM instances with bootimage build
Until now, the bootimage build hasn't supported using the Java
invocation API to create a VM, destroy it, and create another in the
same process. Ideally, we would be able to create multiple VMs
simultaneously without any interference between them. In fact, Avian
is designed to support this for the most part, but there are a few
places we use global, mutable state which prevent this from working.
Most notably, the bootimage is modified in-place at runtime, so the
best we can do without extensive changes is to clean up the bootimage
when the VM is destroyed so it's ready for later instances. Hence
this commit.
Ultimately, we can move towards a fully reentrant VM by making the
bootimage immutable, but this will require some care to avoid
performance regressions. Another challenge is our Posix signal
handlers, which currently rely on a global handle to the VM, since you
can't, to my knowledge, pass a context pointer when registering a
signal handler. Thread local variables won't necessarily help, since
a thread might attatch to more than one VM at a time.
2011-11-10 20:10:53 +00:00
|
|
|
visitAll(t, t->m->rootThread, join);
|
2009-08-19 20:27:03 +00:00
|
|
|
|
|
|
|
enter(t, Thread::ExitState);
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
{ object p = 0;
|
|
|
|
PROTECT(t, p);
|
2009-08-19 20:27:03 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
for (p = t->m->finalizers; p;) {
|
|
|
|
object f = p;
|
|
|
|
p = finalizerNext(t, p);
|
|
|
|
|
|
|
|
void (*function)(Thread*, object);
|
|
|
|
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
|
|
|
|
if (function) {
|
|
|
|
function(t, finalizerTarget(t, f));
|
|
|
|
}
|
2009-12-06 02:40:46 +00:00
|
|
|
}
|
2009-08-19 20:27:03 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
for (p = t->m->tenuredFinalizers; p;) {
|
|
|
|
object f = p;
|
|
|
|
p = finalizerNext(t, p);
|
2009-08-19 20:27:03 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
void (*function)(Thread*, object);
|
|
|
|
memcpy(&function, &finalizerFinalize(t, f), BytesPerWord);
|
|
|
|
if (function) {
|
|
|
|
function(t, finalizerTarget(t, f));
|
|
|
|
}
|
2009-12-06 02:40:46 +00:00
|
|
|
}
|
2009-08-19 20:27:03 +00:00
|
|
|
}
|
|
|
|
|
2010-11-05 19:18:28 +00:00
|
|
|
if (root(t, Machine::VirtualFiles)) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, root(t, Machine::VirtualFiles));
|
|
|
|
++i)
|
|
|
|
{
|
|
|
|
object region = arrayBody(t, root(t, Machine::VirtualFiles), i);
|
|
|
|
if (region) {
|
|
|
|
static_cast<System::Region*>(regionRegion(t, region))->dispose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (object p = root(t, Machine::VirtualFileFinders);
|
|
|
|
p; p = finderNext(t, p))
|
|
|
|
{
|
|
|
|
static_cast<Finder*>(finderFinder(t, p))->dispose();
|
|
|
|
}
|
|
|
|
|
2009-08-19 20:27:03 +00:00
|
|
|
Machine* m = t->m;
|
|
|
|
|
support multiple sequential VM instances with bootimage build
Until now, the bootimage build hasn't supported using the Java
invocation API to create a VM, destroy it, and create another in the
same process. Ideally, we would be able to create multiple VMs
simultaneously without any interference between them. In fact, Avian
is designed to support this for the most part, but there are a few
places we use global, mutable state which prevent this from working.
Most notably, the bootimage is modified in-place at runtime, so the
best we can do without extensive changes is to clean up the bootimage
when the VM is destroyed so it's ready for later instances. Hence
this commit.
Ultimately, we can move towards a fully reentrant VM by making the
bootimage immutable, but this will require some care to avoid
performance regressions. Another challenge is our Posix signal
handlers, which currently rely on a global handle to the VM, since you
can't, to my knowledge, pass a context pointer when registering a
signal handler. Thread local variables won't necessarily help, since
a thread might attatch to more than one VM at a time.
2011-11-10 20:10:53 +00:00
|
|
|
visitAll(t, t->m->rootThread, disposeNoRemove);
|
2009-08-19 20:27:03 +00:00
|
|
|
|
|
|
|
System* s = m->system;
|
|
|
|
Heap* h = m->heap;
|
|
|
|
Processor* p = m->processor;
|
2010-09-10 21:05:29 +00:00
|
|
|
Classpath* c = m->classpath;
|
2010-09-14 16:49:41 +00:00
|
|
|
Finder* bf = m->bootFinder;
|
|
|
|
Finder* af = m->appFinder;
|
2009-08-19 20:27:03 +00:00
|
|
|
|
2010-11-05 19:18:28 +00:00
|
|
|
c->dispose();
|
2009-08-19 20:27:03 +00:00
|
|
|
m->dispose();
|
|
|
|
h->disposeFixies();
|
|
|
|
p->dispose();
|
2010-09-14 16:49:41 +00:00
|
|
|
bf->dispose();
|
|
|
|
af->dispose();
|
2010-11-05 19:18:28 +00:00
|
|
|
h->dispose();
|
2009-08-19 20:27:03 +00:00
|
|
|
s->dispose();
|
|
|
|
}
|
|
|
|
|
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)
|
|
|
|
{
|
2008-07-12 01:21:53 +00:00
|
|
|
unsigned n = t->heapOffset + t->heapIndex + t->backupHeapIndex;
|
2007-08-18 21:24:29 +00:00
|
|
|
|
|
|
|
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) {
|
2007-10-28 19:14:53 +00:00
|
|
|
v->visit(&(t->javaThread));
|
|
|
|
v->visit(&(t->exception));
|
2007-07-07 23:47:35 +00:00
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-17 23:43:48 +00:00
|
|
|
bool
|
2007-11-02 14:15:06 +00:00
|
|
|
walk(Thread*, Heap::Walker* w, uint32_t* mask, unsigned fixedSize,
|
2008-11-11 15:20:49 +00:00
|
|
|
unsigned arrayElementSize, unsigned arrayLength, unsigned start)
|
2007-11-02 14:15:06 +00:00
|
|
|
{
|
|
|
|
unsigned fixedSizeInWords = ceiling(fixedSize, BytesPerWord);
|
|
|
|
unsigned arrayElementSizeInWords
|
|
|
|
= ceiling(arrayElementSize, BytesPerWord);
|
|
|
|
|
2008-11-11 15:20:49 +00:00
|
|
|
for (unsigned i = start; i < fixedSizeInWords; ++i) {
|
2007-11-02 14:15:06 +00:00
|
|
|
if (mask[i / 32] & (static_cast<uint32_t>(1) << (i % 32))) {
|
|
|
|
if (not w->visit(i)) {
|
2009-05-17 23:43:48 +00:00
|
|
|
return false;
|
2007-11-02 14:15:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool arrayObjectElements = false;
|
|
|
|
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
|
|
|
|
unsigned k = fixedSizeInWords + j;
|
|
|
|
if (mask[k / 32] & (static_cast<uint32_t>(1) << (k % 32))) {
|
|
|
|
arrayObjectElements = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (arrayObjectElements) {
|
2008-11-11 15:20:49 +00:00
|
|
|
unsigned arrayStart;
|
|
|
|
unsigned elementStart;
|
|
|
|
if (start > fixedSizeInWords) {
|
|
|
|
unsigned s = start - fixedSizeInWords;
|
|
|
|
arrayStart = s / arrayElementSizeInWords;
|
|
|
|
elementStart = s % arrayElementSizeInWords;
|
|
|
|
} else {
|
|
|
|
arrayStart = 0;
|
|
|
|
elementStart = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = arrayStart; i < arrayLength; ++i) {
|
|
|
|
for (unsigned j = elementStart; j < arrayElementSizeInWords; ++j) {
|
2007-11-02 14:15:06 +00:00
|
|
|
unsigned k = fixedSizeInWords + j;
|
|
|
|
if (mask[k / 32] & (static_cast<uint32_t>(1) << (k % 32))) {
|
|
|
|
if (not w->visit
|
|
|
|
(fixedSizeInWords + (i * arrayElementSizeInWords) + j))
|
|
|
|
{
|
2009-05-17 23:43:48 +00:00
|
|
|
return false;
|
2007-11-02 14:15:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-05-17 23:43:48 +00:00
|
|
|
|
|
|
|
return true;
|
2007-11-02 14:15:06 +00:00
|
|
|
}
|
|
|
|
|
2009-08-03 22:16:41 +00:00
|
|
|
object
|
|
|
|
findInInterfaces(Thread* t, object class_, object name, object spec,
|
|
|
|
object (*find)(Thread*, object, object, object))
|
|
|
|
{
|
|
|
|
object result = 0;
|
|
|
|
if (classInterfaceTable(t, class_)) {
|
|
|
|
for (unsigned i = 0;
|
|
|
|
i < arrayLength(t, classInterfaceTable(t, class_)) and result == 0;
|
|
|
|
i += 2)
|
|
|
|
{
|
|
|
|
result = find
|
|
|
|
(t, arrayBody(t, classInterfaceTable(t, class_), i), name, spec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2007-10-28 01:54:30 +00:00
|
|
|
void
|
|
|
|
finalizerTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
|
2007-07-29 23:32:23 +00:00
|
|
|
{
|
2007-10-28 19:14:53 +00:00
|
|
|
v->visit(&finalizerTarget(t, *p));
|
2007-07-29 23:32:23 +00:00
|
|
|
|
|
|
|
object finalizer = *p;
|
|
|
|
*p = finalizerNext(t, finalizer);
|
2011-03-26 01:11:38 +00:00
|
|
|
|
|
|
|
void (*function)(Thread*, object);
|
|
|
|
memcpy(&function, &finalizerFinalize(t, finalizer), BytesPerWord);
|
|
|
|
|
|
|
|
if (function) {
|
|
|
|
finalizerNext(t, finalizer) = t->m->finalizeQueue;
|
|
|
|
t->m->finalizeQueue = finalizer;
|
|
|
|
} else {
|
|
|
|
set(t, finalizer, FinalizerQueueTarget, finalizerTarget(t, finalizer));
|
|
|
|
set(t, finalizer, FinalizerQueueNext, root(t, Machine::ObjectsToFinalize));
|
|
|
|
setRoot(t, Machine::ObjectsToFinalize, finalizer);
|
|
|
|
}
|
2007-07-29 23:32:23 +00:00
|
|
|
}
|
|
|
|
|
2007-07-20 01:07:30 +00:00
|
|
|
void
|
2007-10-28 01:54:30 +00:00
|
|
|
referenceTargetUnreachable(Thread* t, Heap::Visitor* v, object* p)
|
2007-07-20 01:07:30 +00:00
|
|
|
{
|
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-10-28 19:14:53 +00:00
|
|
|
v->visit(p);
|
2007-07-20 01:07:30 +00:00
|
|
|
jreferenceTarget(t, *p) = 0;
|
|
|
|
|
2011-03-19 21:10:52 +00:00
|
|
|
if (objectClass(t, *p) == type(t, Machine::CleanerType)) {
|
|
|
|
object reference = *p;
|
|
|
|
*p = jreferenceVmNext(t, reference);
|
2011-03-26 01:11:38 +00:00
|
|
|
|
|
|
|
set(t, reference, CleanerQueueNext, root(t, Machine::ObjectsToClean));
|
|
|
|
setRoot(t, Machine::ObjectsToClean, reference);
|
2011-03-19 21:10:52 +00:00
|
|
|
} else {
|
|
|
|
if (jreferenceQueue(t, *p)
|
|
|
|
and t->m->heap->status(jreferenceQueue(t, *p)) != Heap::Unreachable)
|
|
|
|
{
|
|
|
|
// queue is reachable - add the reference
|
2007-07-20 01:07:30 +00:00
|
|
|
|
2011-03-19 21:10:52 +00:00
|
|
|
v->visit(&jreferenceQueue(t, *p));
|
2007-07-20 01:07:30 +00:00
|
|
|
|
2011-03-19 21:10:52 +00:00
|
|
|
object q = jreferenceQueue(t, *p);
|
2007-07-20 01:07:30 +00:00
|
|
|
|
2011-03-19 21:10:52 +00:00
|
|
|
if (referenceQueueFront(t, q)) {
|
|
|
|
set(t, *p, JreferenceJNext, referenceQueueFront(t, q));
|
|
|
|
} else {
|
|
|
|
set(t, *p, JreferenceJNext, *p);
|
|
|
|
}
|
|
|
|
set(t, q, ReferenceQueueFront, *p);
|
|
|
|
|
|
|
|
jreferenceQueue(t, *p) = 0;
|
2007-07-20 01:07:30 +00:00
|
|
|
}
|
|
|
|
|
2011-03-19 21:10:52 +00:00
|
|
|
*p = jreferenceVmNext(t, *p);
|
2007-07-20 01:07:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-20 03:18:25 +00:00
|
|
|
void
|
2007-10-28 01:54:30 +00:00
|
|
|
referenceUnreachable(Thread* t, Heap::Visitor* v, object* p)
|
2007-07-20 03:18:25 +00:00
|
|
|
{
|
2009-09-02 00:32:21 +00:00
|
|
|
object r = static_cast<object>(t->m->heap->follow(*p));
|
|
|
|
|
2007-07-29 23:32:23 +00:00
|
|
|
if (DebugReferences) {
|
|
|
|
fprintf(stderr, "reference %p unreachable (target %p)\n",
|
2009-09-02 00:32:21 +00:00
|
|
|
*p, jreferenceTarget(t, r));
|
2007-07-29 23:32:23 +00:00
|
|
|
}
|
2007-07-21 17:50:26 +00:00
|
|
|
|
2009-09-02 00:32:21 +00:00
|
|
|
if (jreferenceQueue(t, r)
|
|
|
|
and t->m->heap->status(jreferenceQueue(t, r)) != Heap::Unreachable)
|
2007-07-20 03:18:25 +00:00
|
|
|
{
|
|
|
|
// queue is reachable - add the reference
|
2007-10-28 01:54:30 +00:00
|
|
|
referenceTargetUnreachable(t, v, p);
|
2007-07-29 23:32:23 +00:00
|
|
|
} else {
|
2007-11-04 21:15:28 +00:00
|
|
|
*p = jreferenceVmNext(t, *p);
|
2007-07-20 03:18:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-20 01:07:30 +00:00
|
|
|
void
|
2007-10-28 01:54:30 +00:00
|
|
|
referenceTargetReachable(Thread* t, Heap::Visitor* v, object* p)
|
2007-07-20 01:07:30 +00:00
|
|
|
{
|
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-10-28 19:14:53 +00:00
|
|
|
v->visit(p);
|
|
|
|
v->visit(&jreferenceTarget(t, *p));
|
2007-07-20 01:07:30 +00:00
|
|
|
|
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 {
|
2007-10-28 19:14:53 +00:00
|
|
|
v->visit(&jreferenceQueue(t, *p));
|
2007-07-20 01:07:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-10-28 01:54:30 +00:00
|
|
|
bool major = m->heap->collectionType() == Heap::MajorCollection;
|
2007-07-10 01:43:43 +00:00
|
|
|
|
2008-08-11 21:16:55 +00:00
|
|
|
assert(t, m->finalizeQueue == 0);
|
2007-07-29 23:32:23 +00:00
|
|
|
|
2007-07-10 01:43:43 +00:00
|
|
|
object firstNewTenuredFinalizer = 0;
|
|
|
|
object lastNewTenuredFinalizer = 0;
|
|
|
|
|
|
|
|
for (object* p = &(m->finalizers); *p;) {
|
2007-10-28 19:14:53 +00:00
|
|
|
v->visit(p);
|
2007-07-10 01:43:43 +00:00
|
|
|
|
|
|
|
if (m->heap->status(finalizerTarget(t, *p)) == Heap::Unreachable) {
|
|
|
|
// target is unreachable - queue it up for finalization
|
2007-10-28 01:54:30 +00:00
|
|
|
finalizerTargetUnreachable(t, v, p);
|
2007-07-10 01:43:43 +00:00
|
|
|
} else {
|
|
|
|
// target is reachable
|
2007-10-28 19:14:53 +00:00
|
|
|
v->visit(&finalizerTarget(t, *p));
|
2007-07-10 01:43:43 +00:00
|
|
|
|
|
|
|
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
|
2007-10-28 01:54:30 +00:00
|
|
|
referenceUnreachable(t, v, p);
|
2009-09-01 23:23:30 +00:00
|
|
|
} else if (m->heap->status
|
|
|
|
(jreferenceTarget
|
|
|
|
(t, static_cast<object>(m->heap->follow(*p))))
|
2007-08-14 00:37:00 +00:00
|
|
|
== Heap::Unreachable)
|
|
|
|
{
|
2007-07-20 03:18:25 +00:00
|
|
|
// target is unreachable
|
2007-10-28 01:54:30 +00:00
|
|
|
referenceTargetUnreachable(t, v, p);
|
2007-07-10 01:43:43 +00:00
|
|
|
} else {
|
|
|
|
// both reference and target are reachable
|
2007-10-28 01:54:30 +00:00
|
|
|
referenceTargetReachable(t, v, p);
|
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;
|
2007-11-04 21:15:28 +00:00
|
|
|
*p = jreferenceVmNext(t, reference);
|
|
|
|
jreferenceVmNext(t, reference) = firstNewTenuredWeakReference;
|
2007-07-10 01:43:43 +00:00
|
|
|
firstNewTenuredWeakReference = reference;
|
|
|
|
} else {
|
2007-11-04 21:15:28 +00:00
|
|
|
p = &jreferenceVmNext(t, *p);
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-28 01:54:30 +00:00
|
|
|
if (major) {
|
2007-07-10 01:43:43 +00:00
|
|
|
for (object* p = &(m->tenuredFinalizers); *p;) {
|
2007-10-28 19:14:53 +00:00
|
|
|
v->visit(p);
|
2007-07-10 01:43:43 +00:00
|
|
|
|
|
|
|
if (m->heap->status(finalizerTarget(t, *p)) == Heap::Unreachable) {
|
|
|
|
// target is unreachable - queue it up for finalization
|
2007-10-28 01:54:30 +00:00
|
|
|
finalizerTargetUnreachable(t, v, p);
|
2007-07-10 01:43:43 +00:00
|
|
|
} else {
|
|
|
|
// target is reachable
|
2007-10-28 19:14:53 +00:00
|
|
|
v->visit(&finalizerTarget(t, *p));
|
2007-07-10 01:43:43 +00:00
|
|
|
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
|
2007-10-28 01:54:30 +00:00
|
|
|
referenceUnreachable(t, v, p);
|
2009-09-01 23:23:30 +00:00
|
|
|
} else if (m->heap->status
|
|
|
|
(jreferenceTarget
|
|
|
|
(t, static_cast<object>(m->heap->follow(*p))))
|
2007-07-10 01:43:43 +00:00
|
|
|
== Heap::Unreachable)
|
|
|
|
{
|
2007-07-20 03:18:25 +00:00
|
|
|
// target is unreachable
|
2007-10-28 01:54:30 +00:00
|
|
|
referenceTargetUnreachable(t, v, p);
|
2007-07-10 01:43:43 +00:00
|
|
|
} else {
|
2007-07-20 03:18:25 +00:00
|
|
|
// both reference and target are reachable
|
2007-10-28 01:54:30 +00:00
|
|
|
referenceTargetReachable(t, v, p);
|
2007-11-04 21:15:28 +00:00
|
|
|
p = &jreferenceVmNext(t, *p);
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2008-08-11 21:16:55 +00:00
|
|
|
jreferenceVmNext(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
|
2008-11-22 21:47:18 +00:00
|
|
|
t->m->heap->free(t->defaultHeap, ThreadHeapSizeInBytes);
|
2007-09-13 03:15:16 +00:00
|
|
|
t->defaultHeap = static_cast<uintptr_t*>
|
2008-11-22 21:47:18 +00:00
|
|
|
(t->m->heap->allocate(ThreadHeapSizeInBytes));
|
2009-03-04 03:05:48 +00:00
|
|
|
memset(t->defaultHeap, 0, ThreadHeapSizeInBytes);
|
2007-07-16 23:58:37 +00:00
|
|
|
#endif
|
|
|
|
|
2009-03-04 03:05:48 +00:00
|
|
|
if (t->heap == t->defaultHeap) {
|
|
|
|
memset(t->defaultHeap, 0, t->heapIndex * BytesPerWord);
|
|
|
|
} else {
|
|
|
|
memset(t->defaultHeap, 0, ThreadHeapSizeInBytes);
|
|
|
|
t->heap = t->defaultHeap;
|
|
|
|
}
|
|
|
|
|
2007-08-23 02:24:25 +00:00
|
|
|
t->heapOffset = 0;
|
2010-12-27 22:55:23 +00:00
|
|
|
|
|
|
|
if (t->m->heap->limitExceeded()) {
|
|
|
|
// if we're out of memory, pretend the thread-local heap is
|
|
|
|
// already full so we don't make things worse:
|
|
|
|
t->heapIndex = ThreadHeapSizeInWords;
|
|
|
|
} else {
|
|
|
|
t->heapIndex = 0;
|
|
|
|
}
|
2007-07-07 23:47:35 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
if (t->flags & Thread::UseBackupHeapFlag) {
|
2010-06-19 22:40:21 +00:00
|
|
|
memset(t->backupHeap, 0, ThreadBackupHeapSizeInBytes);
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
t->flags &= ~Thread::UseBackupHeapFlag;
|
2008-04-09 19:08:13 +00:00
|
|
|
t->backupHeapIndex = 0;
|
|
|
|
}
|
|
|
|
|
2007-07-07 23:47:35 +00:00
|
|
|
for (Thread* c = t->child; c; c = c->peer) {
|
|
|
|
postCollect(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
uint64_t
|
|
|
|
invoke(Thread* t, uintptr_t* arguments)
|
|
|
|
{
|
2011-03-17 14:49:41 +00:00
|
|
|
object m = *reinterpret_cast<object*>(arguments[0]);
|
|
|
|
object o = *reinterpret_cast<object*>(arguments[1]);
|
2010-12-27 22:55:23 +00:00
|
|
|
|
|
|
|
t->m->processor->invoke(t, m, o);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-07-22 00:57:55 +00:00
|
|
|
void
|
2011-03-19 21:10:52 +00:00
|
|
|
finalizeObject(Thread* t, object o, const char* name)
|
2009-07-22 00:57:55 +00:00
|
|
|
{
|
|
|
|
for (object c = objectClass(t, o); c; c = classSuper(t, c)) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, c)); ++i) {
|
|
|
|
object m = arrayBody(t, classMethodTable(t, c), i);
|
|
|
|
|
2011-03-19 21:10:52 +00:00
|
|
|
if (vm::strcmp(reinterpret_cast<const int8_t*>(name),
|
2009-08-27 00:26:44 +00:00
|
|
|
&byteArrayBody(t, methodName(t, m), 0)) == 0
|
|
|
|
and vm::strcmp(reinterpret_cast<const int8_t*>("()V"),
|
|
|
|
&byteArrayBody(t, methodSpec(t, m), 0)) == 0)
|
2009-07-22 00:57:55 +00:00
|
|
|
{
|
2011-03-17 14:49:41 +00:00
|
|
|
PROTECT(t, m);
|
|
|
|
PROTECT(t, o);
|
|
|
|
|
|
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(&m),
|
|
|
|
reinterpret_cast<uintptr_t>(&o) };
|
2010-12-27 22:55:23 +00:00
|
|
|
|
|
|
|
run(t, invoke, arguments);
|
|
|
|
|
2009-07-22 00:57:55 +00:00
|
|
|
t->exception = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
|
2009-08-14 14:52:31 +00:00
|
|
|
unsigned
|
|
|
|
readByte(Stream& s, unsigned* value)
|
|
|
|
{
|
|
|
|
if (*value == NoByte) {
|
|
|
|
return s.read1();
|
|
|
|
} else {
|
|
|
|
unsigned r = *value;
|
|
|
|
*value = NoByte;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-24 21:05:15 +00:00
|
|
|
object
|
2009-06-04 23:21:42 +00:00
|
|
|
parseUtf8NonAscii(Thread* t, Stream& s, object bytesSoFar, unsigned byteCount,
|
2009-08-14 14:52:31 +00:00
|
|
|
unsigned sourceIndex, unsigned byteA, unsigned byteB)
|
2007-10-24 21:05:15 +00:00
|
|
|
{
|
2009-06-04 23:21:42 +00:00
|
|
|
PROTECT(t, bytesSoFar);
|
|
|
|
|
|
|
|
unsigned length = byteArrayLength(t, bytesSoFar) - 1;
|
|
|
|
object value = makeCharArray(t, length + 1);
|
|
|
|
|
2007-10-24 21:05:15 +00:00
|
|
|
unsigned vi = 0;
|
2009-06-04 23:21:42 +00:00
|
|
|
for (; vi < byteCount; ++vi) {
|
|
|
|
charArrayBody(t, value, vi) = byteArrayBody(t, bytesSoFar, vi);
|
|
|
|
}
|
|
|
|
|
2009-08-14 14:52:31 +00:00
|
|
|
for (unsigned si = sourceIndex; si < length; ++si) {
|
|
|
|
unsigned a = readByte(s, &byteA);
|
2007-10-24 21:05:15 +00:00
|
|
|
if (a & 0x80) {
|
2007-10-25 23:58:53 +00:00
|
|
|
if (a & 0x20) {
|
|
|
|
// 3 bytes
|
|
|
|
si += 2;
|
|
|
|
assert(t, si < length);
|
2009-08-14 14:52:31 +00:00
|
|
|
unsigned b = readByte(s, &byteB);
|
2009-06-04 23:21:42 +00:00
|
|
|
unsigned c = s.read1();
|
|
|
|
charArrayBody(t, value, vi++)
|
|
|
|
= ((a & 0xf) << 12) | ((b & 0x3f) << 6) | (c & 0x3f);
|
2007-10-24 21:05:15 +00:00
|
|
|
} else {
|
2007-10-25 23:58:53 +00:00
|
|
|
// 2 bytes
|
|
|
|
++ si;
|
|
|
|
assert(t, si < length);
|
2009-08-14 14:52:31 +00:00
|
|
|
unsigned b = readByte(s, &byteB);
|
2007-10-25 23:58:53 +00:00
|
|
|
|
|
|
|
if (a == 0xC0 and b == 0x80) {
|
2009-06-04 23:21:42 +00:00
|
|
|
charArrayBody(t, value, vi++) = 0;
|
|
|
|
} else {
|
|
|
|
charArrayBody(t, value, vi++) = ((a & 0x1f) << 6) | (b & 0x3f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
charArrayBody(t, value, vi++) = a;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vi < length) {
|
|
|
|
PROTECT(t, value);
|
|
|
|
|
|
|
|
object v = makeCharArray(t, vi + 1);
|
|
|
|
memcpy(&charArrayBody(t, v, 0), &charArrayBody(t, value, 0), vi * 2);
|
|
|
|
value = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
parseUtf8(Thread* t, Stream& s, unsigned length)
|
|
|
|
{
|
|
|
|
object value = makeByteArray(t, length + 1);
|
|
|
|
unsigned vi = 0;
|
|
|
|
for (unsigned si = 0; si < length; ++si) {
|
|
|
|
unsigned a = s.read1();
|
|
|
|
if (a & 0x80) {
|
|
|
|
if (a & 0x20) {
|
|
|
|
// 3 bytes
|
2009-08-14 14:52:31 +00:00
|
|
|
return parseUtf8NonAscii(t, s, value, vi, si, a, NoByte);
|
2009-06-04 23:21:42 +00:00
|
|
|
} else {
|
|
|
|
// 2 bytes
|
|
|
|
unsigned b = s.read1();
|
|
|
|
|
|
|
|
if (a == 0xC0 and b == 0x80) {
|
|
|
|
++ si;
|
|
|
|
assert(t, si < length);
|
2007-10-25 23:58:53 +00:00
|
|
|
byteArrayBody(t, value, vi++) = 0;
|
|
|
|
} else {
|
2009-08-14 14:52:31 +00:00
|
|
|
return parseUtf8NonAscii(t, s, value, vi, si, a, b);
|
2007-10-25 23:58:53 +00:00
|
|
|
}
|
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);
|
|
|
|
|
2009-03-04 03:05:48 +00:00
|
|
|
object v = makeByteArray(t, vi + 1);
|
2007-10-24 21:05:15 +00:00
|
|
|
memcpy(&byteArrayBody(t, v, 0), &byteArrayBody(t, value, 0), vi);
|
|
|
|
value = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2009-06-07 00:26:23 +00:00
|
|
|
void
|
|
|
|
removeByteArray(Thread* t, object o)
|
|
|
|
{
|
2010-09-14 16:49:41 +00:00
|
|
|
hashMapRemove
|
|
|
|
(t, root(t, Machine::ByteArrayMap), o, byteArrayHash, objectEqual);
|
2009-06-07 00:26:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
internByteArray(Thread* t, object array)
|
|
|
|
{
|
|
|
|
PROTECT(t, array);
|
|
|
|
|
2010-09-17 01:43:27 +00:00
|
|
|
ACQUIRE(t, t->m->referenceLock);
|
|
|
|
|
2009-06-07 00:26:23 +00:00
|
|
|
object n = hashMapFindNode
|
2010-09-14 16:49:41 +00:00
|
|
|
(t, root(t, Machine::ByteArrayMap), array, byteArrayHash, byteArrayEqual);
|
2009-06-07 00:26:23 +00:00
|
|
|
if (n) {
|
|
|
|
return jreferenceTarget(t, tripleFirst(t, n));
|
|
|
|
} else {
|
2010-09-14 16:49:41 +00:00
|
|
|
hashMapInsert(t, root(t, Machine::ByteArrayMap), array, 0, byteArrayHash);
|
2009-06-07 00:26:23 +00:00
|
|
|
addFinalizer(t, array, removeByteArray);
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
unsigned
|
|
|
|
parsePoolEntry(Thread* t, Stream& s, uint32_t* index, object pool, unsigned i)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, pool);
|
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
s.setPosition(index[i]);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
switch (s.read1()) {
|
|
|
|
case CONSTANT_Integer:
|
|
|
|
case CONSTANT_Float: {
|
|
|
|
singletonValue(t, pool, i) = s.read4();
|
|
|
|
} return 1;
|
|
|
|
|
|
|
|
case CONSTANT_Long:
|
|
|
|
case CONSTANT_Double: {
|
|
|
|
uint64_t v = s.read8();
|
|
|
|
memcpy(&singletonValue(t, pool, i), &v, 8);
|
|
|
|
} return 2;
|
|
|
|
|
|
|
|
case CONSTANT_Utf8: {
|
|
|
|
if (singletonObject(t, pool, i) == 0) {
|
|
|
|
object value = parseUtf8(t, s, s.read2());
|
2010-09-14 16:49:41 +00:00
|
|
|
if (objectClass(t, value) == type(t, Machine::ByteArrayType)) {
|
2009-06-07 00:26:23 +00:00
|
|
|
value = internByteArray(t, value);
|
|
|
|
}
|
2007-11-05 21:40:17 +00:00
|
|
|
set(t, pool, SingletonBody + (i * BytesPerWord), value);
|
|
|
|
}
|
|
|
|
} return 1;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
case CONSTANT_Class: {
|
|
|
|
if (singletonObject(t, pool, i) == 0) {
|
|
|
|
unsigned si = s.read2() - 1;
|
|
|
|
parsePoolEntry(t, s, index, pool, si);
|
|
|
|
|
2009-08-18 20:26:28 +00:00
|
|
|
object value = makeReference(t, 0, singletonObject(t, pool, si), 0);
|
2007-11-05 21:40:17 +00:00
|
|
|
set(t, pool, SingletonBody + (i * BytesPerWord), value);
|
|
|
|
}
|
|
|
|
} return 1;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
case CONSTANT_String: {
|
|
|
|
if (singletonObject(t, pool, i) == 0) {
|
|
|
|
unsigned si = s.read2() - 1;
|
|
|
|
parsePoolEntry(t, s, index, pool, si);
|
|
|
|
|
|
|
|
object value = singletonObject(t, pool, si);
|
2010-09-10 21:05:29 +00:00
|
|
|
value = t->m->classpath->makeString
|
|
|
|
(t, value, 0, cast<uintptr_t>(value, BytesPerWord) - 1);
|
2007-11-05 21:40:17 +00:00
|
|
|
value = intern(t, value);
|
|
|
|
set(t, pool, SingletonBody + (i * BytesPerWord), value);
|
|
|
|
}
|
|
|
|
} return 1;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
case CONSTANT_NameAndType: {
|
|
|
|
if (singletonObject(t, pool, i) == 0) {
|
|
|
|
unsigned ni = s.read2() - 1;
|
|
|
|
unsigned ti = s.read2() - 1;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
parsePoolEntry(t, s, index, pool, ni);
|
|
|
|
parsePoolEntry(t, s, index, pool, ti);
|
|
|
|
|
|
|
|
object name = singletonObject(t, pool, ni);
|
|
|
|
object type = singletonObject(t, pool, ti);
|
|
|
|
object value = makePair(t, name, type);
|
|
|
|
set(t, pool, SingletonBody + (i * BytesPerWord), value);
|
|
|
|
}
|
|
|
|
} return 1;
|
|
|
|
|
|
|
|
case CONSTANT_Fieldref:
|
|
|
|
case CONSTANT_Methodref:
|
|
|
|
case CONSTANT_InterfaceMethodref: {
|
|
|
|
if (singletonObject(t, pool, i) == 0) {
|
|
|
|
unsigned ci = s.read2() - 1;
|
|
|
|
unsigned nti = s.read2() - 1;
|
|
|
|
|
|
|
|
parsePoolEntry(t, s, index, pool, ci);
|
|
|
|
parsePoolEntry(t, s, index, pool, nti);
|
|
|
|
|
2009-08-18 20:26:28 +00:00
|
|
|
object class_ = referenceName(t, singletonObject(t, pool, ci));
|
2007-11-05 21:40:17 +00:00
|
|
|
object nameAndType = singletonObject(t, pool, nti);
|
|
|
|
object value = makeReference
|
|
|
|
(t, class_, pairFirst(t, nameAndType), pairSecond(t, nameAndType));
|
|
|
|
set(t, pool, SingletonBody + (i * BytesPerWord), value);
|
|
|
|
}
|
|
|
|
} return 1;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
object
|
|
|
|
parsePool(Thread* t, Stream& s)
|
|
|
|
{
|
|
|
|
unsigned count = s.read2() - 1;
|
2009-10-18 02:11:03 +00:00
|
|
|
object pool = makeSingletonOfSize(t, count + poolMaskSize(count));
|
2008-01-13 22:05:08 +00:00
|
|
|
PROTECT(t, pool);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
if (count) {
|
2008-04-13 18:15:04 +00:00
|
|
|
uint32_t* index = static_cast<uint32_t*>(t->m->heap->allocate(count * 4));
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
THREAD_RESOURCE2(t, uint32_t*, index, unsigned, count,
|
|
|
|
t->m->heap->free(index, count * 4));
|
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
|
|
index[i] = s.position();
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
switch (s.read1()) {
|
|
|
|
case CONSTANT_Class:
|
|
|
|
case CONSTANT_String:
|
|
|
|
singletonMarkObject(t, pool, i);
|
|
|
|
s.skip(2);
|
|
|
|
break;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
case CONSTANT_Integer:
|
2009-08-10 19:20:23 +00:00
|
|
|
s.skip(4);
|
|
|
|
break;
|
2009-10-18 02:11:03 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
case CONSTANT_Float:
|
2009-10-18 02:11:03 +00:00
|
|
|
singletonSetBit(t, pool, count, i);
|
2007-11-05 21:40:17 +00:00
|
|
|
s.skip(4);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CONSTANT_NameAndType:
|
2007-07-14 17:31:01 +00:00
|
|
|
case CONSTANT_Fieldref:
|
|
|
|
case CONSTANT_Methodref:
|
2007-11-05 21:40:17 +00:00
|
|
|
case CONSTANT_InterfaceMethodref:
|
|
|
|
singletonMarkObject(t, pool, i);
|
|
|
|
s.skip(4);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CONSTANT_Long:
|
2009-08-10 19:20:23 +00:00
|
|
|
s.skip(8);
|
|
|
|
++ i;
|
|
|
|
break;
|
2010-12-27 22:55:23 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
case CONSTANT_Double:
|
2009-10-18 02:11:03 +00:00
|
|
|
singletonSetBit(t, pool, count, i);
|
|
|
|
singletonSetBit(t, pool, count, i + 1);
|
2007-11-05 21:40:17 +00:00
|
|
|
s.skip(8);
|
|
|
|
++ i;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CONSTANT_Utf8:
|
|
|
|
singletonMarkObject(t, pool, i);
|
|
|
|
s.skip(s.read2());
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: abort(t);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
2007-11-05 21:40:17 +00:00
|
|
|
|
|
|
|
unsigned end = s.position();
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < count;) {
|
|
|
|
i += parsePoolEntry(t, s, index, pool, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
s.setPosition(end);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-10 03:20:56 +00:00
|
|
|
object
|
|
|
|
getClassAddendum(Thread* t, object class_, object pool)
|
|
|
|
{
|
|
|
|
object addendum = classAddendum(t, class_);
|
|
|
|
if (addendum == 0) {
|
2011-07-10 00:01:00 +00:00
|
|
|
PROTECT(t, class_);
|
|
|
|
|
2011-04-10 03:20:56 +00:00
|
|
|
addendum = makeClassAddendum(t, pool, 0, 0, 0, 0, 0);
|
|
|
|
set(t, class_, ClassAddendum, addendum);
|
|
|
|
}
|
|
|
|
return addendum;
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
void
|
2011-03-18 03:42:15 +00:00
|
|
|
parseInterfaceTable(Thread* t, Stream& s, object class_, object pool,
|
|
|
|
Machine::Type throwType)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
2007-11-27 22:23:00 +00:00
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned count = s.read2();
|
2011-03-28 02:29:31 +00:00
|
|
|
object table = 0;
|
|
|
|
PROTECT(t, table);
|
|
|
|
|
|
|
|
if (count) {
|
|
|
|
table = makeArray(t, count);
|
2011-04-10 03:20:56 +00:00
|
|
|
|
|
|
|
object addendum = getClassAddendum(t, class_, pool);
|
|
|
|
set(t, addendum, ClassAddendumInterfaceTable, table);
|
2011-03-28 02:29:31 +00:00
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
2009-08-18 20:26:28 +00:00
|
|
|
object name = referenceName(t, singletonObject(t, pool, s.read2() - 1));
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, name);
|
|
|
|
|
2011-03-18 03:42:15 +00:00
|
|
|
object interface = resolveClass
|
|
|
|
(t, classLoader(t, class_), name, true, throwType);
|
2009-08-04 14:50:04 +00:00
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, interface);
|
|
|
|
|
2011-03-28 02:29:31 +00:00
|
|
|
set(t, table, ArrayBody + (i * BytesPerWord), interface);
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
hashMapInsertMaybe(t, map, name, interface, byteArrayHash, byteArrayEqual);
|
|
|
|
|
|
|
|
addInterfaces(t, interface, map);
|
|
|
|
}
|
|
|
|
|
|
|
|
object interfaceTable = 0;
|
|
|
|
if (hashMapSize(t, map)) {
|
2009-09-19 00:01:54 +00:00
|
|
|
unsigned length = hashMapSize(t, map);
|
2007-07-14 17:31:01 +00:00
|
|
|
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
|
|
|
|
length *= 2;
|
|
|
|
}
|
2009-03-04 03:05:48 +00:00
|
|
|
interfaceTable = makeArray(t, length);
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, interfaceTable);
|
|
|
|
|
|
|
|
unsigned i = 0;
|
2008-11-22 23:38:41 +00:00
|
|
|
for (HashMapIterator it(t, map); it.hasMore();) {
|
2010-09-25 21:54:01 +00:00
|
|
|
object interface = tripleSecond(t, it.next());
|
2007-07-14 17:31:01 +00:00
|
|
|
|
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
|
2009-03-04 03:05:48 +00:00
|
|
|
(t, arrayLength(t, classVirtualTable(t, interface)));
|
2007-08-14 00:37:00 +00:00
|
|
|
|
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) {
|
2007-11-02 21:08:14 +00:00
|
|
|
unsigned staticOffset = BytesPerWord * 2;
|
|
|
|
unsigned staticCount = 0;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2009-03-04 03:05:48 +00:00
|
|
|
object fieldTable = makeArray(t, count);
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, fieldTable);
|
|
|
|
|
2009-03-04 03:05:48 +00:00
|
|
|
object staticValueTable = makeIntArray(t, count);
|
2007-10-25 19:20:39 +00:00
|
|
|
PROTECT(t, staticValueTable);
|
|
|
|
|
2009-09-19 00:01:54 +00:00
|
|
|
object addendum = 0;
|
|
|
|
PROTECT(t, addendum);
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, uint8_t, staticTypes, count);
|
2007-11-02 21:08:14 +00:00
|
|
|
|
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-11-06 15:29:05 +00:00
|
|
|
unsigned value = 0;
|
2007-10-25 19:20:39 +00:00
|
|
|
|
2011-03-18 03:42:15 +00:00
|
|
|
addendum = 0;
|
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
unsigned code = fieldCode
|
|
|
|
(t, byteArrayBody(t, singletonObject(t, pool, spec - 1), 0));
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned attributeCount = s.read2();
|
|
|
|
for (unsigned j = 0; j < attributeCount; ++j) {
|
2007-11-05 21:40:17 +00:00
|
|
|
object name = singletonObject(t, pool, s.read2() - 1);
|
2007-10-25 19:20:39 +00:00
|
|
|
unsigned length = s.read4();
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
if (vm::strcmp(reinterpret_cast<const int8_t*>("ConstantValue"),
|
|
|
|
&byteArrayBody(t, name, 0)) == 0)
|
2007-10-25 19:20:39 +00:00
|
|
|
{
|
2007-11-06 15:29:05 +00:00
|
|
|
value = s.read2();
|
2011-03-18 03:42:15 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("Signature"),
|
|
|
|
&byteArrayBody(t, name, 0)) == 0)
|
|
|
|
{
|
|
|
|
if (addendum == 0) {
|
|
|
|
addendum = makeFieldAddendum(t, pool, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
set(t, addendum, AddendumSignature,
|
|
|
|
singletonObject(t, pool, s.read2() - 1));
|
2009-09-19 00:01:54 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
|
|
|
|
("RuntimeVisibleAnnotations"),
|
|
|
|
&byteArrayBody(t, name, 0)) == 0)
|
|
|
|
{
|
2011-03-18 03:42:15 +00:00
|
|
|
if (addendum == 0) {
|
|
|
|
addendum = makeFieldAddendum(t, pool, 0, 0);
|
|
|
|
}
|
|
|
|
|
2009-09-19 22:21:15 +00:00
|
|
|
object body = makeByteArray(t, length);
|
|
|
|
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)),
|
|
|
|
length);
|
2011-03-18 03:42:15 +00:00
|
|
|
|
|
|
|
set(t, addendum, AddendumAnnotationTable, body);
|
2007-10-25 19:20:39 +00:00
|
|
|
} 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
|
2007-11-02 21:08:14 +00:00
|
|
|
code,
|
2007-07-14 17:31:01 +00:00
|
|
|
flags,
|
|
|
|
0, // offset
|
2011-03-16 01:34:00 +00:00
|
|
|
0, // native ID
|
2007-11-05 21:40:17 +00:00
|
|
|
singletonObject(t, pool, name - 1),
|
|
|
|
singletonObject(t, pool, spec - 1),
|
2009-09-19 00:01:54 +00:00
|
|
|
addendum,
|
2007-07-14 17:31:01 +00:00
|
|
|
class_);
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
unsigned size = fieldSize(t, code);
|
2007-07-14 17:31:01 +00:00
|
|
|
if (flags & ACC_STATIC) {
|
2011-09-28 17:12:21 +00:00
|
|
|
unsigned excess = (staticOffset % size) % BytesPerWord;
|
|
|
|
if (excess) {
|
|
|
|
staticOffset += BytesPerWord - excess;
|
2007-11-02 21:08:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fieldOffset(t, field) = staticOffset;
|
|
|
|
|
|
|
|
staticOffset += size;
|
|
|
|
|
2007-11-06 15:29:05 +00:00
|
|
|
intArrayBody(t, staticValueTable, staticCount) = value;
|
2007-11-02 21:08:14 +00:00
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
RUNTIME_ARRAY_BODY(staticTypes)[staticCount++] = code;
|
2007-07-14 17:31:01 +00:00
|
|
|
} else {
|
2009-03-03 03:18:15 +00:00
|
|
|
if (flags & ACC_FINAL) {
|
2009-08-18 20:26:28 +00:00
|
|
|
classVmFlags(t, class_) |= HasFinalMemberFlag;
|
2009-03-03 03:18:15 +00:00
|
|
|
}
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
while (memberOffset % size) {
|
2010-09-10 21:05:29 +00:00
|
|
|
++ memberOffset;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fieldOffset(t, field) = memberOffset;
|
2011-08-30 01:00:17 +00:00
|
|
|
|
|
|
|
memberOffset += size;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2007-11-02 21:08:14 +00:00
|
|
|
if (staticCount) {
|
|
|
|
unsigned footprint = ceiling(staticOffset - (BytesPerWord * 2),
|
|
|
|
BytesPerWord);
|
2009-03-04 03:05:48 +00:00
|
|
|
object staticTable = makeSingletonOfSize(t, footprint);
|
2007-11-02 21:08:14 +00:00
|
|
|
|
|
|
|
uint8_t* body = reinterpret_cast<uint8_t*>
|
|
|
|
(&singletonBody(t, staticTable, 0));
|
|
|
|
|
|
|
|
for (unsigned i = 0, offset = 0; i < staticCount; ++i) {
|
2009-08-27 00:26:44 +00:00
|
|
|
unsigned size = fieldSize(t, RUNTIME_ARRAY_BODY(staticTypes)[i]);
|
2007-11-02 21:08:14 +00:00
|
|
|
unsigned excess = offset % size;
|
|
|
|
if (excess) {
|
|
|
|
offset += BytesPerWord - excess;
|
|
|
|
}
|
|
|
|
|
2007-11-06 15:29:05 +00:00
|
|
|
unsigned value = intArrayBody(t, staticValueTable, i);
|
2007-11-02 21:08:14 +00:00
|
|
|
if (value) {
|
2009-08-27 00:26:44 +00:00
|
|
|
switch (RUNTIME_ARRAY_BODY(staticTypes)[i]) {
|
2007-11-02 21:08:14 +00:00
|
|
|
case ByteField:
|
|
|
|
case BooleanField:
|
2007-11-06 15:29:05 +00:00
|
|
|
body[offset] = singletonValue(t, pool, value - 1);
|
2007-11-02 21:08:14 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CharField:
|
|
|
|
case ShortField:
|
2007-11-06 15:29:05 +00:00
|
|
|
*reinterpret_cast<uint16_t*>(body + offset)
|
|
|
|
= singletonValue(t, pool, value - 1);
|
2007-11-02 21:08:14 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IntField:
|
|
|
|
case FloatField:
|
2007-11-06 15:29:05 +00:00
|
|
|
*reinterpret_cast<uint32_t*>(body + offset)
|
|
|
|
= singletonValue(t, pool, value - 1);
|
2007-11-02 21:08:14 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LongField:
|
|
|
|
case DoubleField:
|
2007-11-06 15:29:05 +00:00
|
|
|
memcpy(body + offset, &singletonValue(t, pool, value - 1), 8);
|
2007-11-02 21:08:14 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case ObjectField:
|
2007-11-06 15:29:05 +00:00
|
|
|
memcpy(body + offset,
|
|
|
|
&singletonObject(t, pool, value - 1),
|
|
|
|
BytesPerWord);
|
2007-11-02 21:08:14 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
if (RUNTIME_ARRAY_BODY(staticTypes)[i] == ObjectField) {
|
2007-11-05 21:40:17 +00:00
|
|
|
singletonMarkObject(t, staticTable, offset / BytesPerWord);
|
2007-11-02 21:08:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
offset += size;
|
|
|
|
}
|
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
|
2009-03-04 03:05:48 +00:00
|
|
|
(t, ceiling(classFixedSize(t, class_), 32 * BytesPerWord));
|
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();
|
|
|
|
|
2011-01-30 21:14:57 +00:00
|
|
|
object code = makeCode(t, pool, 0, 0, 0, maxStack, maxLocals, length);
|
2007-07-14 17:31:01 +00:00
|
|
|
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) {
|
2009-03-04 03:05:48 +00:00
|
|
|
object eht = makeExceptionHandlerTable(t, ehtLength);
|
2007-07-14 17:31:01 +00:00
|
|
|
for (unsigned i = 0; i < ehtLength; ++i) {
|
2011-08-30 01:00:17 +00:00
|
|
|
unsigned start = s.read2();
|
|
|
|
unsigned end = s.read2();
|
|
|
|
unsigned ip = s.read2();
|
|
|
|
unsigned catchType = s.read2();
|
|
|
|
exceptionHandlerTableBody(t, eht, i) = exceptionHandler
|
|
|
|
(start, end, ip, catchType);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
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) {
|
2007-11-05 21:40:17 +00:00
|
|
|
object name = singletonObject(t, pool, s.read2() - 1);
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned length = s.read4();
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
if (vm::strcmp(reinterpret_cast<const int8_t*>("LineNumberTable"),
|
|
|
|
&byteArrayBody(t, name, 0)) == 0)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
|
|
|
unsigned lntLength = s.read2();
|
2009-03-04 03:05:48 +00:00
|
|
|
object lnt = makeLineNumberTable(t, lntLength);
|
2007-07-14 17:31:01 +00:00
|
|
|
for (unsigned i = 0; i < lntLength; ++i) {
|
2011-08-30 01:00:17 +00:00
|
|
|
unsigned ip = s.read2();
|
|
|
|
unsigned line = s.read2();
|
|
|
|
lineNumberTableBody(t, lnt, i) = lineNumber(ip, line);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2009-08-10 13:56:16 +00:00
|
|
|
object
|
|
|
|
addInterfaceMethods(Thread* t, object class_, object virtualMap,
|
|
|
|
unsigned* virtualCount, bool makeList)
|
|
|
|
{
|
|
|
|
object itable = classInterfaceTable(t, class_);
|
|
|
|
if (itable) {
|
|
|
|
PROTECT(t, class_);
|
|
|
|
PROTECT(t, virtualMap);
|
|
|
|
PROTECT(t, itable);
|
|
|
|
|
|
|
|
object list = 0;
|
|
|
|
PROTECT(t, list);
|
|
|
|
|
|
|
|
object method = 0;
|
|
|
|
PROTECT(t, method);
|
|
|
|
|
|
|
|
object vtable = 0;
|
|
|
|
PROTECT(t, vtable);
|
|
|
|
|
|
|
|
unsigned stride = (classFlags(t, class_) & ACC_INTERFACE) ? 1 : 2;
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, itable); i += stride) {
|
|
|
|
vtable = classVirtualTable(t, arrayBody(t, itable, i));
|
|
|
|
if (vtable) {
|
|
|
|
for (unsigned j = 0; j < arrayLength(t, vtable); ++j) {
|
|
|
|
method = arrayBody(t, vtable, j);
|
|
|
|
object n = hashMapFindNode
|
|
|
|
(t, virtualMap, method, methodHash, methodEqual);
|
|
|
|
if (n == 0) {
|
|
|
|
method = makeMethod
|
|
|
|
(t,
|
|
|
|
methodVmFlags(t, method),
|
|
|
|
methodReturnCode(t, method),
|
|
|
|
methodParameterCount(t, method),
|
|
|
|
methodParameterFootprint(t, method),
|
|
|
|
methodFlags(t, method),
|
|
|
|
(*virtualCount)++,
|
|
|
|
0,
|
2010-11-26 19:41:31 +00:00
|
|
|
0,
|
2009-08-10 13:56:16 +00:00
|
|
|
methodName(t, method),
|
|
|
|
methodSpec(t, method),
|
2009-09-19 00:01:54 +00:00
|
|
|
0,
|
2009-08-10 13:56:16 +00:00
|
|
|
class_,
|
|
|
|
0);
|
|
|
|
|
|
|
|
hashMapInsert(t, virtualMap, method, method, methodHash);
|
|
|
|
|
|
|
|
if (makeList) {
|
|
|
|
if (list == 0) {
|
|
|
|
list = vm::makeList(t, 0, 0, 0);
|
|
|
|
}
|
|
|
|
listAppend(t, list, method);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
unsigned virtualCount = 0;
|
|
|
|
unsigned declaredVirtualCount = 0;
|
|
|
|
|
|
|
|
object superVirtualTable = 0;
|
|
|
|
PROTECT(t, superVirtualTable);
|
|
|
|
|
|
|
|
if (classFlags(t, class_) & ACC_INTERFACE) {
|
2009-08-10 13:56:16 +00:00
|
|
|
addInterfaceMethods(t, class_, virtualMap, &virtualCount, false);
|
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) {
|
2009-03-04 03:05:48 +00:00
|
|
|
object methodTable = makeArray(t, count);
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, methodTable);
|
|
|
|
|
2009-09-19 00:01:54 +00:00
|
|
|
object addendum = 0;
|
|
|
|
PROTECT(t, addendum);
|
|
|
|
|
|
|
|
object code = 0;
|
|
|
|
PROTECT(t, code);
|
|
|
|
|
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();
|
|
|
|
|
2011-03-18 03:42:15 +00:00
|
|
|
addendum = 0;
|
2009-09-19 00:01:54 +00:00
|
|
|
code = 0;
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned attributeCount = s.read2();
|
|
|
|
for (unsigned j = 0; j < attributeCount; ++j) {
|
2011-09-01 03:15:41 +00:00
|
|
|
object attributeName = singletonObject(t, pool, s.read2() - 1);
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned length = s.read4();
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
if (vm::strcmp(reinterpret_cast<const int8_t*>("Code"),
|
2011-09-01 03:15:41 +00:00
|
|
|
&byteArrayBody(t, attributeName, 0)) == 0)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
|
|
|
code = parseCode(t, s, pool);
|
2010-09-10 21:05:29 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("Exceptions"),
|
2011-09-01 03:15:41 +00:00
|
|
|
&byteArrayBody(t, attributeName, 0)) == 0)
|
2010-09-10 21:05:29 +00:00
|
|
|
{
|
|
|
|
if (addendum == 0) {
|
2011-03-18 03:42:15 +00:00
|
|
|
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0);
|
2010-09-10 21:05:29 +00:00
|
|
|
}
|
|
|
|
unsigned exceptionCount = s.read2();
|
|
|
|
object body = makeShortArray(t, exceptionCount);
|
|
|
|
for (unsigned i = 0; i < exceptionCount; ++i) {
|
|
|
|
shortArrayBody(t, body, i) = s.read2();
|
|
|
|
}
|
|
|
|
set(t, addendum, MethodAddendumExceptionTable, body);
|
2011-03-18 03:42:15 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
|
|
|
|
("AnnotationDefault"),
|
2011-09-01 03:15:41 +00:00
|
|
|
&byteArrayBody(t, attributeName, 0)) == 0)
|
2011-03-18 03:42:15 +00:00
|
|
|
{
|
|
|
|
if (addendum == 0) {
|
|
|
|
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
object body = makeByteArray(t, length);
|
|
|
|
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)),
|
|
|
|
length);
|
|
|
|
|
|
|
|
set(t, addendum, MethodAddendumAnnotationDefault, body);
|
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("Signature"),
|
2011-09-01 03:15:41 +00:00
|
|
|
&byteArrayBody(t, attributeName, 0)) == 0)
|
2011-03-18 03:42:15 +00:00
|
|
|
{
|
|
|
|
if (addendum == 0) {
|
|
|
|
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
set(t, addendum, AddendumSignature,
|
|
|
|
singletonObject(t, pool, s.read2() - 1));
|
2009-09-19 00:01:54 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
|
|
|
|
("RuntimeVisibleAnnotations"),
|
2011-09-01 03:15:41 +00:00
|
|
|
&byteArrayBody(t, attributeName, 0)) == 0)
|
2009-09-19 00:01:54 +00:00
|
|
|
{
|
2010-09-10 21:05:29 +00:00
|
|
|
if (addendum == 0) {
|
2011-03-18 03:42:15 +00:00
|
|
|
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0);
|
2010-09-10 21:05:29 +00:00
|
|
|
}
|
2011-03-18 03:42:15 +00:00
|
|
|
|
2009-09-19 22:21:15 +00:00
|
|
|
object body = makeByteArray(t, length);
|
|
|
|
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)),
|
|
|
|
length);
|
2011-03-18 03:42:15 +00:00
|
|
|
|
2010-09-10 21:05:29 +00:00
|
|
|
set(t, addendum, AddendumAnnotationTable, body);
|
2007-07-14 17:31:01 +00:00
|
|
|
} else {
|
|
|
|
s.skip(length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
const char* specString = reinterpret_cast<const char*>
|
2007-11-05 21:40:17 +00:00
|
|
|
(&byteArrayBody(t, singletonObject(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-11-05 21:40:17 +00:00
|
|
|
object method = t->m->processor->makeMethod
|
|
|
|
(t,
|
|
|
|
0, // vm flags
|
|
|
|
returnCode,
|
|
|
|
parameterCount,
|
2007-11-20 22:24:02 +00:00
|
|
|
parameterFootprint(t, specString, flags & ACC_STATIC),
|
2007-11-05 21:40:17 +00:00
|
|
|
flags,
|
|
|
|
0, // offset
|
|
|
|
singletonObject(t, pool, name - 1),
|
|
|
|
singletonObject(t, pool, spec - 1),
|
2009-09-19 00:01:54 +00:00
|
|
|
addendum,
|
2007-11-05 21:40:17 +00:00
|
|
|
class_,
|
|
|
|
code);
|
2007-10-01 15:19:15 +00:00
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, method);
|
|
|
|
|
2007-11-05 14:28:46 +00:00
|
|
|
if (methodVirtual(t, method)) {
|
2007-07-14 17:31:01 +00:00
|
|
|
++ 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);
|
|
|
|
}
|
2009-07-22 00:57:55 +00:00
|
|
|
|
2009-08-13 15:17:05 +00:00
|
|
|
if (UNLIKELY((classFlags(t, class_) & ACC_INTERFACE) == 0
|
2009-08-27 00:26:44 +00:00
|
|
|
and vm::strcmp
|
2009-07-22 00:57:55 +00:00
|
|
|
(reinterpret_cast<const int8_t*>("finalize"),
|
|
|
|
&byteArrayBody(t, methodName(t, method), 0)) == 0
|
2009-08-27 00:26:44 +00:00
|
|
|
and vm::strcmp
|
2009-07-22 00:57:55 +00:00
|
|
|
(reinterpret_cast<const int8_t*>("()V"),
|
|
|
|
&byteArrayBody(t, methodSpec(t, method), 0)) == 0
|
|
|
|
and (not emptyMethod(t, method))))
|
|
|
|
{
|
|
|
|
classVmFlags(t, class_) |= HasFinalizerFlag;
|
|
|
|
}
|
2007-11-05 14:28:46 +00:00
|
|
|
} else {
|
|
|
|
methodOffset(t, method) = i;
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
if (vm::strcmp(reinterpret_cast<const int8_t*>("<clinit>"),
|
|
|
|
&byteArrayBody(t, methodName(t, method), 0)) == 0)
|
2007-11-05 14:28:46 +00:00
|
|
|
{
|
|
|
|
methodVmFlags(t, method) |= ClassInitFlag;
|
|
|
|
classVmFlags(t, class_) |= NeedInitFlag;
|
2009-08-27 00:26:44 +00:00
|
|
|
} else if (vm::strcmp
|
|
|
|
(reinterpret_cast<const int8_t*>("<init>"),
|
|
|
|
&byteArrayBody(t, methodName(t, method), 0)) == 0)
|
2009-03-03 03:18:15 +00:00
|
|
|
{
|
|
|
|
methodVmFlags(t, method) |= ConstructorFlag;
|
2007-11-05 14:28:46 +00:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, class_, ClassMethodTable, methodTable);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2009-08-10 13:56:16 +00:00
|
|
|
object abstractVirtuals;
|
|
|
|
if (classFlags(t, class_) & ACC_INTERFACE) {
|
|
|
|
abstractVirtuals = 0;
|
|
|
|
} else {
|
|
|
|
abstractVirtuals = addInterfaceMethods
|
|
|
|
(t, class_, virtualMap, &virtualCount, true);
|
|
|
|
}
|
|
|
|
PROTECT(t, abstractVirtuals);
|
|
|
|
|
2008-01-28 15:12:06 +00:00
|
|
|
bool populateInterfaceVtables = false;
|
|
|
|
|
2007-08-14 13:27:10 +00:00
|
|
|
if (declaredVirtualCount == 0
|
2010-09-25 22:35:18 +00:00
|
|
|
and abstractVirtuals == 0
|
2007-08-14 13:27:10 +00:00
|
|
|
and (classFlags(t, class_) & ACC_INTERFACE) == 0)
|
|
|
|
{
|
2008-01-21 23:42:12 +00:00
|
|
|
if (classSuper(t, class_)) {
|
|
|
|
// inherit virtual table from superclass
|
|
|
|
set(t, class_, ClassVirtualTable, superVirtualTable);
|
|
|
|
|
|
|
|
if (classInterfaceTable(t, classSuper(t, class_))
|
|
|
|
and arrayLength(t, classInterfaceTable(t, class_))
|
2009-09-19 00:01:54 +00:00
|
|
|
== arrayLength
|
|
|
|
(t, classInterfaceTable(t, classSuper(t, class_))))
|
2008-01-21 23:42:12 +00:00
|
|
|
{
|
|
|
|
// inherit interface table from superclass
|
|
|
|
set(t, class_, ClassInterfaceTable,
|
|
|
|
classInterfaceTable(t, classSuper(t, class_)));
|
2008-01-28 15:12:06 +00:00
|
|
|
} else {
|
|
|
|
populateInterfaceVtables = true;
|
|
|
|
}
|
2008-01-21 23:42:12 +00:00
|
|
|
} else {
|
2008-01-28 15:12:06 +00:00
|
|
|
// apparently, Object does not have any virtual methods. We
|
|
|
|
// give it a vtable anyway so code doesn't break elsewhere.
|
2009-03-04 03:05:48 +00:00
|
|
|
object vtable = makeArray(t, 0);
|
2008-01-21 23:42:12 +00:00
|
|
|
set(t, class_, ClassVirtualTable, vtable);
|
2007-11-27 22:23:00 +00:00
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
} else if (virtualCount) {
|
|
|
|
// generate class vtable
|
|
|
|
|
2009-03-04 03:05:48 +00:00
|
|
|
object vtable = makeArray(t, virtualCount);
|
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);
|
|
|
|
|
2008-11-22 23:38:41 +00:00
|
|
|
for (HashMapIterator it(t, virtualMap); it.hasMore();) {
|
|
|
|
object method = tripleFirst(t, it.next());
|
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 {
|
2009-08-10 13:56:16 +00:00
|
|
|
populateInterfaceVtables = true;
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
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
|
|
|
}
|
2009-08-10 13:56:16 +00:00
|
|
|
|
|
|
|
if (abstractVirtuals) {
|
2009-09-19 00:01:54 +00:00
|
|
|
PROTECT(t, vtable);
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2011-04-10 03:20:56 +00:00
|
|
|
object addendum = getClassAddendum(t, class_, pool);
|
|
|
|
set(t, addendum, ClassAddendumMethodTable,
|
|
|
|
classMethodTable(t, class_));
|
|
|
|
|
2009-08-10 13:56:16 +00:00
|
|
|
unsigned oldLength = arrayLength(t, classMethodTable(t, class_));
|
|
|
|
object newMethodTable = makeArray
|
|
|
|
(t, oldLength + listSize(t, abstractVirtuals));
|
|
|
|
|
|
|
|
memcpy(&arrayBody(t, newMethodTable, 0),
|
|
|
|
&arrayBody(t, classMethodTable(t, class_), 0),
|
|
|
|
oldLength * sizeof(object));
|
|
|
|
|
|
|
|
mark(t, newMethodTable, ArrayBody, oldLength);
|
|
|
|
|
|
|
|
unsigned mti = oldLength;
|
|
|
|
for (object p = listFront(t, abstractVirtuals);
|
|
|
|
p; p = pairSecond(t, p))
|
|
|
|
{
|
|
|
|
set(t, newMethodTable,
|
|
|
|
ArrayBody + ((mti++) * BytesPerWord), pairFirst(t, p));
|
|
|
|
|
|
|
|
set(t, vtable,
|
|
|
|
ArrayBody + ((i++) * BytesPerWord), pairFirst(t, p));
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(t, arrayLength(t, newMethodTable) == mti);
|
|
|
|
|
|
|
|
set(t, class_, ClassMethodTable, newMethodTable);
|
|
|
|
}
|
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);
|
2008-01-28 15:12:06 +00:00
|
|
|
}
|
|
|
|
|
2008-03-21 23:42:36 +00:00
|
|
|
if (populateInterfaceVtables) {
|
2008-01-28 15:12:06 +00:00
|
|
|
// generate interface vtables
|
|
|
|
object itable = classInterfaceTable(t, class_);
|
|
|
|
if (itable) {
|
|
|
|
PROTECT(t, itable);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
|
|
|
object ivtable = classVirtualTable(t, arrayBody(t, itable, i));
|
|
|
|
if (ivtable) {
|
|
|
|
object vtable = arrayBody(t, itable, i + 1);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2008-01-28 15:12:06 +00:00
|
|
|
for (unsigned j = 0; j < arrayLength(t, ivtable); ++j) {
|
|
|
|
object method = arrayBody(t, ivtable, j);
|
|
|
|
method = hashMapFind
|
|
|
|
(t, virtualMap, method, methodHash, methodEqual);
|
2009-08-10 13:56:16 +00:00
|
|
|
assert(t, method);
|
2007-08-14 00:37:00 +00:00
|
|
|
|
2009-09-19 00:01:54 +00:00
|
|
|
set(t, vtable, ArrayBody + (j * BytesPerWord), method);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-08-27 22:26:25 +00:00
|
|
|
void
|
|
|
|
parseAttributeTable(Thread* t, Stream& s, object class_, object pool)
|
|
|
|
{
|
2011-03-18 03:42:15 +00:00
|
|
|
PROTECT(t, class_);
|
|
|
|
PROTECT(t, pool);
|
|
|
|
|
2009-08-27 22:26:25 +00:00
|
|
|
unsigned attributeCount = s.read2();
|
|
|
|
for (unsigned j = 0; j < attributeCount; ++j) {
|
|
|
|
object name = singletonObject(t, pool, s.read2() - 1);
|
|
|
|
unsigned length = s.read4();
|
|
|
|
|
|
|
|
if (vm::strcmp(reinterpret_cast<const int8_t*>("SourceFile"),
|
|
|
|
&byteArrayBody(t, name, 0)) == 0)
|
|
|
|
{
|
|
|
|
set(t, class_, ClassSourceFile, singletonObject(t, pool, s.read2() - 1));
|
2011-03-18 03:42:15 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("Signature"),
|
|
|
|
&byteArrayBody(t, name, 0)) == 0)
|
|
|
|
{
|
2011-04-10 03:20:56 +00:00
|
|
|
object addendum = getClassAddendum(t, class_, pool);
|
2011-03-18 03:42:15 +00:00
|
|
|
set(t, addendum, AddendumSignature,
|
|
|
|
singletonObject(t, pool, s.read2() - 1));
|
2011-04-01 01:47:26 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("InnerClasses"),
|
|
|
|
&byteArrayBody(t, name, 0)) == 0)
|
|
|
|
{
|
|
|
|
unsigned innerClassCount = s.read2();
|
|
|
|
object table = makeArray(t, innerClassCount);
|
|
|
|
PROTECT(t, table);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < innerClassCount; ++i) {
|
|
|
|
int16_t inner = s.read2();
|
|
|
|
int16_t outer = s.read2();
|
|
|
|
int16_t name = s.read2();
|
|
|
|
int16_t flags = s.read2();
|
|
|
|
|
|
|
|
object reference = makeInnerClassReference
|
|
|
|
(t, inner ? singletonObject(t, pool, inner - 1) : 0,
|
|
|
|
outer ? singletonObject(t, pool, outer - 1) : 0,
|
|
|
|
name ? singletonObject(t, pool, name - 1) : 0,
|
|
|
|
flags);
|
|
|
|
|
|
|
|
set(t, table, ArrayBody + (i * BytesPerWord), reference);
|
|
|
|
}
|
|
|
|
|
2011-04-10 03:20:56 +00:00
|
|
|
object addendum = getClassAddendum(t, class_, pool);
|
2011-04-01 01:47:26 +00:00
|
|
|
set(t, addendum, ClassAddendumInnerClassTable, table);
|
2009-09-19 00:01:54 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>
|
|
|
|
("RuntimeVisibleAnnotations"),
|
|
|
|
&byteArrayBody(t, name, 0)) == 0)
|
|
|
|
{
|
2009-09-19 22:21:15 +00:00
|
|
|
object body = makeByteArray(t, length);
|
2011-04-10 03:20:56 +00:00
|
|
|
PROTECT(t, body);
|
2009-09-19 22:21:15 +00:00
|
|
|
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, body, 0)), length);
|
|
|
|
|
2011-04-10 03:20:56 +00:00
|
|
|
object addendum = getClassAddendum(t, class_, pool);
|
2011-03-18 03:42:15 +00:00
|
|
|
set(t, addendum, AddendumAnnotationTable, body);
|
2009-08-27 22:26:25 +00:00
|
|
|
} else {
|
|
|
|
s.skip(length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
void
|
|
|
|
updateClassTables(Thread* t, object newClass, object oldClass)
|
|
|
|
{
|
|
|
|
object fieldTable = classFieldTable(t, newClass);
|
|
|
|
if (fieldTable) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, fieldTable); ++i) {
|
|
|
|
set(t, arrayBody(t, fieldTable, i), FieldClass, newClass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (classFlags(t, newClass) & ACC_INTERFACE) {
|
|
|
|
object virtualTable = classVirtualTable(t, newClass);
|
|
|
|
if (virtualTable) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, virtualTable); ++i) {
|
|
|
|
if (methodClass(t, arrayBody(t, virtualTable, i)) == oldClass) {
|
|
|
|
set(t, arrayBody(t, virtualTable, i), MethodClass, newClass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
object methodTable = classMethodTable(t, newClass);
|
|
|
|
if (methodTable) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, methodTable); ++i) {
|
|
|
|
set(t, arrayBody(t, methodTable, i), MethodClass, newClass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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_));
|
2007-11-05 21:40:17 +00:00
|
|
|
|
2010-09-10 21:05:29 +00:00
|
|
|
expect(t, classFixedSize(t, bootstrapClass) >= classFixedSize(t, class_));
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2009-07-22 00:57:55 +00:00
|
|
|
expect(t, (classVmFlags(t, class_) & HasFinalizerFlag) == 0);
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, bootstrapClass);
|
|
|
|
PROTECT(t, class_);
|
|
|
|
|
|
|
|
ENTER(t, Thread::ExclusiveState);
|
|
|
|
|
2007-11-05 15:39:48 +00:00
|
|
|
classVmFlags(t, bootstrapClass) &= ~BootstrapFlag;
|
|
|
|
classVmFlags(t, bootstrapClass) |= classVmFlags(t, class_);
|
2009-05-16 08:03:03 +00:00
|
|
|
classFlags(t, bootstrapClass) |= classFlags(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_));
|
2011-03-18 03:42:15 +00:00
|
|
|
set(t, bootstrapClass, ClassAddendum, classAddendum(t, class_));
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
updateClassTables(t, bootstrapClass, class_);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
2009-08-10 13:56:16 +00:00
|
|
|
makeArrayClass(Thread* t, object loader, unsigned dimensions, object spec,
|
2007-07-14 17:31:01 +00:00
|
|
|
object elementClass)
|
|
|
|
{
|
2007-08-20 02:57:32 +00:00
|
|
|
// todo: arrays should implement Cloneable and Serializable
|
2010-09-14 16:49:41 +00:00
|
|
|
|
|
|
|
if (classVmFlags(t, type(t, Machine::JobjectType)) & BootstrapFlag) {
|
2010-09-17 01:43:27 +00:00
|
|
|
PROTECT(t, loader);
|
2010-09-14 16:49:41 +00:00
|
|
|
PROTECT(t, spec);
|
|
|
|
PROTECT(t, elementClass);
|
|
|
|
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-10 02:38:12 +00:00
|
|
|
// Load java.lang.Object if present so we can use its vtable, but
|
|
|
|
// don't throw an exception if we can't find it. This way, we
|
|
|
|
// avoid infinite recursion due to trying to create an array to
|
|
|
|
// make a stack trace for a ClassNotFoundException.
|
2010-09-14 16:49:41 +00:00
|
|
|
resolveSystemClass
|
|
|
|
(t, root(t, Machine::BootLoader),
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-10 02:38:12 +00:00
|
|
|
className(t, type(t, Machine::JobjectType)), false);
|
2010-09-14 16:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object vtable = classVirtualTable(t, type(t, Machine::JobjectType));
|
2007-11-05 21:40:17 +00:00
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
object c = t->m->processor->makeClass
|
2007-07-14 17:31:01 +00:00
|
|
|
(t,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
2 * BytesPerWord,
|
|
|
|
BytesPerWord,
|
2009-08-18 20:26:28 +00:00
|
|
|
dimensions,
|
2010-09-14 16:49:41 +00:00
|
|
|
classObjectMask(t, type(t, Machine::ArrayType)),
|
2007-07-14 17:31:01 +00:00
|
|
|
spec,
|
2009-08-27 22:26:25 +00:00
|
|
|
0,
|
2010-09-14 16:49:41 +00:00
|
|
|
type(t, Machine::JobjectType),
|
2007-07-14 17:31:01 +00:00
|
|
|
0,
|
2007-11-05 21:40:17 +00:00
|
|
|
vtable,
|
2007-07-14 17:31:01 +00:00
|
|
|
0,
|
2007-07-30 23:19:05 +00:00
|
|
|
0,
|
2009-09-19 00:01:54 +00:00
|
|
|
0,
|
2007-08-20 02:57:32 +00:00
|
|
|
elementClass,
|
2009-08-10 13:56:16 +00:00
|
|
|
loader,
|
2007-11-05 21:40:17 +00:00
|
|
|
arrayLength(t, vtable));
|
2007-12-11 21:26:59 +00:00
|
|
|
|
2011-07-10 00:01:00 +00:00
|
|
|
PROTECT(t, c);
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
t->m->processor->initVtable(t, c);
|
|
|
|
|
|
|
|
return c;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2011-03-27 05:21:37 +00:00
|
|
|
void
|
|
|
|
saveLoadedClass(Thread* t, object loader, object c)
|
|
|
|
{
|
|
|
|
PROTECT(t, loader);
|
|
|
|
PROTECT(t, c);
|
|
|
|
|
|
|
|
ACQUIRE(t, t->m->classLock);
|
|
|
|
|
|
|
|
if (classLoaderMap(t, loader) == 0) {
|
|
|
|
object map = makeHashMap(t, 0, 0);
|
|
|
|
set(t, loader, ClassLoaderMap, map);
|
|
|
|
}
|
|
|
|
|
|
|
|
hashMapInsert
|
|
|
|
(t, classLoaderMap(t, loader), className(t, c), c, byteArrayHash);
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
object
|
2011-03-18 03:42:15 +00:00
|
|
|
makeArrayClass(Thread* t, object loader, object spec, bool throw_,
|
|
|
|
Machine::Type throwType)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
2009-09-18 18:20:35 +00:00
|
|
|
PROTECT(t, loader);
|
2007-07-14 17:31:01 +00:00
|
|
|
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;
|
|
|
|
|
2009-03-04 03:05:48 +00:00
|
|
|
elementSpec = makeByteArray(t, s - elementSpecStart + 1);
|
2007-07-14 17:31:01 +00:00
|
|
|
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;
|
2009-03-04 03:05:48 +00:00
|
|
|
elementSpec = makeByteArray(t, 3);
|
2007-07-14 17:31:01 +00:00
|
|
|
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
|
2010-09-14 16:49:41 +00:00
|
|
|
(t, root(t, Machine::BootstrapClassMap), elementSpec, byteArrayHash,
|
|
|
|
byteArrayEqual);
|
2010-09-22 19:58:46 +00:00
|
|
|
|
2007-07-14 18:37:04 +00:00
|
|
|
if (elementClass == 0) {
|
2011-03-18 03:42:15 +00:00
|
|
|
elementClass = resolveClass(t, loader, elementSpec, throw_, throwType);
|
2010-09-14 16:49:41 +00:00
|
|
|
if (elementClass == 0) return 0;
|
2007-07-14 18:37:04 +00:00
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2010-09-22 19:58:46 +00:00
|
|
|
PROTECT(t, elementClass);
|
|
|
|
|
2011-03-27 05:21:37 +00:00
|
|
|
ACQUIRE(t, t->m->classLock);
|
|
|
|
|
2010-09-22 19:58:46 +00:00
|
|
|
object class_ = findLoadedClass(t, classLoader(t, elementClass), spec);
|
2011-03-27 05:21:37 +00:00
|
|
|
if (class_) {
|
|
|
|
return class_;
|
|
|
|
}
|
2010-09-15 00:52:57 +00:00
|
|
|
|
2011-03-27 05:21:37 +00:00
|
|
|
class_ = makeArrayClass
|
2010-09-15 00:52:57 +00:00
|
|
|
(t, classLoader(t, elementClass), dimensions, spec, elementClass);
|
2011-03-27 05:21:37 +00:00
|
|
|
|
|
|
|
PROTECT(t, class_);
|
|
|
|
|
|
|
|
saveLoadedClass(t, classLoader(t, elementClass), class_);
|
|
|
|
|
|
|
|
return class_;
|
2009-08-10 13:56:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
2011-03-18 03:42:15 +00:00
|
|
|
resolveArrayClass(Thread* t, object loader, object spec, bool throw_,
|
|
|
|
Machine::Type throwType)
|
2009-08-10 13:56:16 +00:00
|
|
|
{
|
|
|
|
object c = hashMapFind
|
2010-09-14 16:49:41 +00:00
|
|
|
(t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash,
|
|
|
|
byteArrayEqual);
|
2009-08-10 13:56:16 +00:00
|
|
|
|
|
|
|
if (c) {
|
|
|
|
set(t, c, ClassVirtualTable,
|
2010-09-14 16:49:41 +00:00
|
|
|
classVirtualTable(t, type(t, Machine::JobjectType)));
|
2009-08-10 13:56:16 +00:00
|
|
|
|
|
|
|
return c;
|
|
|
|
} else {
|
2011-01-17 16:36:03 +00:00
|
|
|
PROTECT(t, loader);
|
|
|
|
PROTECT(t, spec);
|
|
|
|
|
|
|
|
c = findLoadedClass(t, root(t, Machine::BootLoader), spec);
|
|
|
|
|
|
|
|
if (c) {
|
|
|
|
return c;
|
|
|
|
} else {
|
2011-03-18 03:42:15 +00:00
|
|
|
return makeArrayClass(t, loader, spec, throw_, throwType);
|
2011-01-17 16:36:03 +00:00
|
|
|
}
|
2009-08-10 13:56:16 +00:00
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
removeMonitor(Thread* t, object o)
|
|
|
|
{
|
2008-01-19 20:12:16 +00:00
|
|
|
unsigned hash;
|
|
|
|
if (DebugMonitors) {
|
|
|
|
hash = objectHash(t, o);
|
|
|
|
}
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
object m = hashMapRemove
|
|
|
|
(t, root(t, Machine::MonitorMap), o, objectHash, objectEqual);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
|
|
|
if (DebugMonitors) {
|
2010-02-05 00:56:21 +00:00
|
|
|
fprintf(stderr, "dispose monitor %p for object %x\n", m, hash);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-29 00:02:32 +00:00
|
|
|
void
|
|
|
|
removeString(Thread* t, object o)
|
|
|
|
{
|
2010-09-14 16:49:41 +00:00
|
|
|
hashMapRemove(t, root(t, Machine::StringMap), o, stringHash, objectEqual);
|
2007-09-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
2007-11-04 21:15:28 +00:00
|
|
|
void
|
|
|
|
bootClass(Thread* t, Machine::Type type, int superType, uint32_t objectMask,
|
2007-11-05 21:40:17 +00:00
|
|
|
unsigned fixedSize, unsigned arrayElementSize, unsigned vtableLength)
|
2007-11-04 21:15:28 +00:00
|
|
|
{
|
2010-09-14 16:49:41 +00:00
|
|
|
object super = (superType >= 0
|
|
|
|
? vm::type(t, static_cast<Machine::Type>(superType)) : 0);
|
2007-11-06 15:29:05 +00:00
|
|
|
|
2007-11-04 21:15:28 +00:00
|
|
|
object mask;
|
|
|
|
if (objectMask) {
|
2007-11-06 15:29:05 +00:00
|
|
|
if (super
|
|
|
|
and classObjectMask(t, super)
|
|
|
|
and intArrayBody(t, classObjectMask(t, super), 0)
|
|
|
|
== static_cast<int32_t>(objectMask))
|
|
|
|
{
|
2010-09-14 16:49:41 +00:00
|
|
|
mask = classObjectMask
|
|
|
|
(t, vm::type(t, static_cast<Machine::Type>(superType)));
|
2007-11-06 15:29:05 +00:00
|
|
|
} else {
|
2009-03-04 03:05:48 +00:00
|
|
|
mask = makeIntArray(t, 1);
|
2007-11-06 15:29:05 +00:00
|
|
|
intArrayBody(t, mask, 0) = objectMask;
|
|
|
|
}
|
2007-11-04 21:15:28 +00:00
|
|
|
} else {
|
|
|
|
mask = 0;
|
|
|
|
}
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
super = (superType >= 0
|
|
|
|
? vm::type(t, static_cast<Machine::Type>(superType)) : 0);
|
2007-11-04 21:15:28 +00:00
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
object class_ = t->m->processor->makeClass
|
2009-12-06 02:40:46 +00:00
|
|
|
(t, 0, BootstrapFlag, fixedSize, arrayElementSize,
|
|
|
|
arrayElementSize ? 1 : 0, mask, 0, 0, super, 0, 0, 0, 0, 0, 0,
|
2010-09-14 16:49:41 +00:00
|
|
|
root(t, Machine::BootLoader), vtableLength);
|
2007-11-04 21:15:28 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
setType(t, type, class_);
|
2007-11-04 21:15:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-11-05 14:28:46 +00:00
|
|
|
bootJavaClass(Thread* t, Machine::Type type, int superType, const char* name,
|
|
|
|
int vtableLength, object bootMethod)
|
2007-11-04 21:15:28 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, bootMethod);
|
|
|
|
|
|
|
|
object n = makeByteArray(t, name);
|
2010-12-10 05:17:57 +00:00
|
|
|
PROTECT(t, n);
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
object class_ = vm::type(t, type);
|
2010-12-10 05:17:57 +00:00
|
|
|
PROTECT(t, class_);
|
2007-11-04 21:15:28 +00:00
|
|
|
|
|
|
|
set(t, class_, ClassName, n);
|
|
|
|
|
2007-11-05 14:28:46 +00:00
|
|
|
object vtable;
|
|
|
|
if (vtableLength >= 0) {
|
2009-03-04 03:05:48 +00:00
|
|
|
vtable = makeArray(t, vtableLength);
|
2007-11-05 14:28:46 +00:00
|
|
|
for (int i = 0; i < vtableLength; ++ i) {
|
|
|
|
arrayBody(t, vtable, i) = bootMethod;
|
|
|
|
}
|
|
|
|
} else {
|
2010-09-14 16:49:41 +00:00
|
|
|
vtable = classVirtualTable
|
|
|
|
(t, vm::type(t, static_cast<Machine::Type>(superType)));
|
2007-11-04 21:15:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
set(t, class_, ClassVirtualTable, vtable);
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
t->m->processor->initVtable(t, class_);
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
hashMapInsert
|
|
|
|
(t, root(t, Machine::BootstrapClassMap), n, class_, byteArrayHash);
|
2007-11-04 21:15:28 +00:00
|
|
|
}
|
|
|
|
|
2010-11-16 16:31:49 +00:00
|
|
|
void
|
|
|
|
nameClass(Thread* t, Machine::Type type, const char* name)
|
|
|
|
{
|
|
|
|
object n = makeByteArray(t, name);
|
|
|
|
set(t, arrayBody(t, t->m->types, type), ClassName, n);
|
|
|
|
}
|
|
|
|
|
2008-11-28 22:02:45 +00:00
|
|
|
void
|
|
|
|
boot(Thread* t)
|
|
|
|
{
|
|
|
|
Machine* m = t->m;
|
|
|
|
|
2008-11-29 23:08:14 +00:00
|
|
|
m->unsafe = true;
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
m->roots = allocate(t, pad((Machine::RootCount + 2) * BytesPerWord), true);
|
|
|
|
arrayLength(t, m->roots) = Machine::RootCount;
|
|
|
|
|
|
|
|
setRoot(t, Machine::BootLoader,
|
|
|
|
allocate(t, FixedSizeOfSystemClassLoader, true));
|
|
|
|
|
|
|
|
setRoot(t, Machine::AppLoader,
|
|
|
|
allocate(t, FixedSizeOfSystemClassLoader, true));
|
2008-11-28 22:02:45 +00:00
|
|
|
|
|
|
|
m->types = allocate(t, pad((TypeCount + 2) * BytesPerWord), true);
|
|
|
|
arrayLength(t, m->types) = TypeCount;
|
|
|
|
|
|
|
|
#include "type-initializations.cpp"
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
object arrayClass = type(t, Machine::ArrayType);
|
2008-11-28 22:02:45 +00:00
|
|
|
set(t, m->types, 0, arrayClass);
|
2010-09-14 16:49:41 +00:00
|
|
|
set(t, m->roots, 0, arrayClass);
|
2008-11-28 22:02:45 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
object loaderClass = type(t, Machine::SystemClassLoaderType);
|
|
|
|
set(t, root(t, Machine::BootLoader), 0, loaderClass);
|
|
|
|
set(t, root(t, Machine::AppLoader), 0, loaderClass);
|
2008-11-28 22:02:45 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
object objectClass = type(t, Machine::JobjectType);
|
2009-12-25 00:57:07 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
object classClass = type(t, Machine::ClassType);
|
2008-11-28 22:02:45 +00:00
|
|
|
set(t, classClass, 0, classClass);
|
|
|
|
set(t, classClass, ClassSuper, objectClass);
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
object intArrayClass = type(t, Machine::IntArrayType);
|
2008-11-28 22:02:45 +00:00
|
|
|
set(t, intArrayClass, 0, classClass);
|
|
|
|
set(t, intArrayClass, ClassSuper, objectClass);
|
|
|
|
|
|
|
|
m->unsafe = false;
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::SingletonType))
|
2008-11-28 22:02:45 +00:00
|
|
|
|= SingletonFlag;
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::ContinuationType))
|
2009-05-03 20:57:11 +00:00
|
|
|
|= ContinuationFlag;
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::JreferenceType))
|
2008-11-28 22:02:45 +00:00
|
|
|
|= ReferenceFlag;
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::WeakReferenceType))
|
2008-11-28 22:02:45 +00:00
|
|
|
|= ReferenceFlag | WeakReferenceFlag;
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::SoftReferenceType))
|
2009-08-13 15:17:05 +00:00
|
|
|
|= ReferenceFlag | WeakReferenceFlag;
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::PhantomReferenceType))
|
2008-11-28 22:02:45 +00:00
|
|
|
|= ReferenceFlag | WeakReferenceFlag;
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::JbooleanType))
|
2008-11-28 22:02:45 +00:00
|
|
|
|= PrimitiveFlag;
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::JbyteType))
|
2008-11-28 22:02:45 +00:00
|
|
|
|= PrimitiveFlag;
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::JcharType))
|
2008-11-28 22:02:45 +00:00
|
|
|
|= PrimitiveFlag;
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::JshortType))
|
2008-11-28 22:02:45 +00:00
|
|
|
|= PrimitiveFlag;
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::JintType))
|
2008-11-28 22:02:45 +00:00
|
|
|
|= PrimitiveFlag;
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::JlongType))
|
2008-11-28 22:02:45 +00:00
|
|
|
|= PrimitiveFlag;
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::JfloatType))
|
2008-11-28 22:02:45 +00:00
|
|
|
|= PrimitiveFlag;
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::JdoubleType))
|
2008-11-28 22:02:45 +00:00
|
|
|
|= PrimitiveFlag;
|
2010-09-14 16:49:41 +00:00
|
|
|
classVmFlags(t, type(t, Machine::JvoidType))
|
2008-11-28 22:02:45 +00:00
|
|
|
|= PrimitiveFlag;
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
set(t, type(t, Machine::BooleanArrayType), ClassStaticTable,
|
|
|
|
type(t, Machine::JbooleanType));
|
|
|
|
set(t, type(t, Machine::ByteArrayType), ClassStaticTable,
|
|
|
|
type(t, Machine::JbyteType));
|
|
|
|
set(t, type(t, Machine::CharArrayType), ClassStaticTable,
|
|
|
|
type(t, Machine::JcharType));
|
|
|
|
set(t, type(t, Machine::ShortArrayType), ClassStaticTable,
|
|
|
|
type(t, Machine::JshortType));
|
|
|
|
set(t, type(t, Machine::IntArrayType), ClassStaticTable,
|
|
|
|
type(t, Machine::JintType));
|
|
|
|
set(t, type(t, Machine::LongArrayType), ClassStaticTable,
|
|
|
|
type(t, Machine::JlongType));
|
|
|
|
set(t, type(t, Machine::FloatArrayType), ClassStaticTable,
|
|
|
|
type(t, Machine::JfloatType));
|
|
|
|
set(t, type(t, Machine::DoubleArrayType), ClassStaticTable,
|
|
|
|
type(t, Machine::JdoubleType));
|
|
|
|
|
2010-09-22 19:58:46 +00:00
|
|
|
{ object map = makeHashMap(t, 0, 0);
|
|
|
|
set(t, root(t, Machine::BootLoader), ClassLoaderMap, map);
|
|
|
|
}
|
|
|
|
|
|
|
|
systemClassLoaderFinder(t, root(t, Machine::BootLoader)) = m->bootFinder;
|
2010-09-14 16:49:41 +00:00
|
|
|
|
|
|
|
{ object map = makeHashMap(t, 0, 0);
|
|
|
|
set(t, root(t, Machine::AppLoader), ClassLoaderMap, map);
|
|
|
|
}
|
|
|
|
|
2010-09-22 19:58:46 +00:00
|
|
|
systemClassLoaderFinder(t, root(t, Machine::AppLoader)) = m->appFinder;
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
set(t, root(t, Machine::AppLoader), ClassLoaderParent,
|
|
|
|
root(t, Machine::BootLoader));
|
|
|
|
|
|
|
|
setRoot(t, Machine::BootstrapClassMap, makeHashMap(t, 0, 0));
|
|
|
|
|
|
|
|
setRoot(t, Machine::StringMap, makeWeakHashMap(t, 0, 0));
|
2010-12-27 22:55:23 +00:00
|
|
|
|
2011-09-20 22:30:30 +00:00
|
|
|
m->processor->boot(t, 0, 0);
|
2008-12-04 02:09:57 +00:00
|
|
|
|
2011-01-30 21:14:57 +00:00
|
|
|
{ object bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 1);
|
2008-11-28 22:02:45 +00:00
|
|
|
codeBody(t, bootCode, 0) = impdep1;
|
|
|
|
object bootMethod = makeMethod
|
2010-11-26 19:41:31 +00:00
|
|
|
(t, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, bootCode);
|
2008-11-28 22:02:45 +00:00
|
|
|
PROTECT(t, bootMethod);
|
|
|
|
|
|
|
|
#include "type-java-initializations.cpp"
|
2010-11-16 16:31:49 +00:00
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
//#ifdef AVIAN_HEAPDUMP
|
2010-11-16 16:31:49 +00:00
|
|
|
# include "type-name-initializations.cpp"
|
2011-08-30 01:00:17 +00:00
|
|
|
//#endif
|
2008-11-28 22:02:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-28 19:14:53 +00:00
|
|
|
class HeapClient: public Heap::Client {
|
|
|
|
public:
|
|
|
|
HeapClient(Machine* m): m(m) { }
|
|
|
|
|
|
|
|
virtual void visitRoots(Heap::Visitor* v) {
|
2008-11-11 15:20:49 +00:00
|
|
|
::visitRoots(m, v);
|
2007-10-28 19:14:53 +00:00
|
|
|
|
|
|
|
postVisit(m->rootThread, v);
|
|
|
|
}
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
virtual void collect(void* context, Heap::CollectionType type) {
|
2008-05-05 13:04:53 +00:00
|
|
|
collect(static_cast<Thread*>(context), type);
|
2008-01-13 22:05:08 +00:00
|
|
|
}
|
|
|
|
|
2007-10-28 19:14:53 +00:00
|
|
|
virtual bool isFixed(void* p) {
|
|
|
|
return objectFixed(m->rootThread, static_cast<object>(p));
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual unsigned sizeInWords(void* p) {
|
|
|
|
Thread* t = m->rootThread;
|
|
|
|
|
|
|
|
object o = static_cast<object>(m->heap->follow(mask(p)));
|
|
|
|
|
|
|
|
unsigned n = baseSize(t, o, static_cast<object>
|
|
|
|
(m->heap->follow(objectClass(t, o))));
|
|
|
|
|
|
|
|
if (objectExtended(t, o)) {
|
|
|
|
++ n;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual unsigned copiedSizeInWords(void* p) {
|
|
|
|
Thread* t = m->rootThread;
|
|
|
|
|
|
|
|
object o = static_cast<object>(m->heap->follow(mask(p)));
|
|
|
|
assert(t, not objectFixed(t, o));
|
|
|
|
|
|
|
|
unsigned n = baseSize(t, o, static_cast<object>
|
|
|
|
(m->heap->follow(objectClass(t, o))));
|
|
|
|
|
|
|
|
if (objectExtended(t, o) or hashTaken(t, o)) {
|
|
|
|
++ n;
|
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void copy(void* srcp, void* dstp) {
|
|
|
|
Thread* t = m->rootThread;
|
|
|
|
|
|
|
|
object src = static_cast<object>(m->heap->follow(mask(srcp)));
|
|
|
|
assert(t, not objectFixed(t, src));
|
|
|
|
|
|
|
|
object class_ = static_cast<object>
|
|
|
|
(m->heap->follow(objectClass(t, src)));
|
|
|
|
|
|
|
|
unsigned base = baseSize(t, src, class_);
|
|
|
|
unsigned n = extendedSize(t, src, base);
|
|
|
|
|
|
|
|
object dst = static_cast<object>(dstp);
|
|
|
|
|
|
|
|
memcpy(dst, src, n * BytesPerWord);
|
|
|
|
|
|
|
|
if (hashTaken(t, src)) {
|
2011-02-14 18:47:59 +00:00
|
|
|
alias(dst, 0) &= PointerMask;
|
|
|
|
alias(dst, 0) |= ExtendedMark;
|
2007-10-28 19:14:53 +00:00
|
|
|
extendedWord(t, dst, base) = takeHash(t, src);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void walk(void* p, Heap::Walker* w) {
|
|
|
|
object o = static_cast<object>(m->heap->follow(mask(p)));
|
2008-11-11 15:20:49 +00:00
|
|
|
::walk(m->rootThread, w, o, 0);
|
2007-10-28 19:14:53 +00:00
|
|
|
}
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
void dispose() {
|
2008-04-13 18:15:04 +00:00
|
|
|
m->heap->free(this, sizeof(*this));
|
2007-10-28 19:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Machine* m;
|
|
|
|
};
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
void
|
|
|
|
doCollect(Thread* t, Heap::CollectionType type)
|
|
|
|
{
|
2011-03-26 01:11:38 +00:00
|
|
|
expect(t, not t->m->collecting);
|
|
|
|
|
|
|
|
t->m->collecting = true;
|
|
|
|
THREAD_RESOURCE0(t, t->m->collecting = false);
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
#ifdef VM_STRESS
|
2011-03-17 14:49:41 +00:00
|
|
|
bool stress = (t->flags & Thread::StressFlag) != 0;
|
2010-12-27 22:55:23 +00:00
|
|
|
if (not stress) atomicOr(&(t->flags), Thread::StressFlag);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
Machine* m = t->m;
|
|
|
|
|
|
|
|
m->unsafe = true;
|
|
|
|
m->heap->collect(type, footprint(m->rootThread));
|
|
|
|
m->unsafe = false;
|
|
|
|
|
|
|
|
postCollect(m->rootThread);
|
|
|
|
|
|
|
|
killZombies(t, m->rootThread);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < m->heapPoolIndex; ++i) {
|
|
|
|
m->heap->free(m->heapPool[i], ThreadHeapSizeInBytes);
|
|
|
|
}
|
|
|
|
m->heapPoolIndex = 0;
|
|
|
|
|
|
|
|
if (m->heap->limitExceeded()) {
|
|
|
|
// if we're out of memory, disallow further allocations of fixed
|
|
|
|
// objects:
|
|
|
|
m->fixedFootprint = FixedFootprintThresholdInBytes;
|
|
|
|
} else {
|
|
|
|
m->fixedFootprint = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef VM_STRESS
|
|
|
|
if (not stress) atomicAnd(&(t->flags), ~Thread::StressFlag);
|
|
|
|
#endif
|
|
|
|
|
2011-03-19 21:10:52 +00:00
|
|
|
object finalizeQueue = t->m->finalizeQueue;
|
2010-12-27 22:55:23 +00:00
|
|
|
t->m->finalizeQueue = 0;
|
2011-03-19 21:10:52 +00:00
|
|
|
for (; finalizeQueue; finalizeQueue = finalizerNext(t, finalizeQueue)) {
|
2010-12-27 22:55:23 +00:00
|
|
|
void (*function)(Thread*, object);
|
2011-03-19 21:10:52 +00:00
|
|
|
memcpy(&function, &finalizerFinalize(t, finalizeQueue), BytesPerWord);
|
2011-03-26 01:11:38 +00:00
|
|
|
function(t, finalizerTarget(t, finalizeQueue));
|
2010-12-27 22:55:23 +00:00
|
|
|
}
|
|
|
|
|
2011-03-26 01:11:38 +00:00
|
|
|
if ((root(t, Machine::ObjectsToFinalize) or root(t, Machine::ObjectsToClean))
|
|
|
|
and m->finalizeThread == 0)
|
|
|
|
{
|
2010-12-27 22:55:23 +00:00
|
|
|
m->finalizeThread = m->processor->makeThread
|
|
|
|
(m, root(t, Machine::FinalizerThread), m->rootThread);
|
|
|
|
|
|
|
|
addThread(t, m->finalizeThread);
|
|
|
|
|
|
|
|
if (not startThread(t, m->finalizeThread)) {
|
|
|
|
removeThread(t, m->finalizeThread);
|
|
|
|
m->finalizeThread = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-15 23:52:02 +00:00
|
|
|
uint64_t
|
|
|
|
invokeLoadClass(Thread* t, uintptr_t* arguments)
|
|
|
|
{
|
|
|
|
object method = reinterpret_cast<object>(arguments[0]);
|
|
|
|
object loader = reinterpret_cast<object>(arguments[1]);
|
|
|
|
object specString = reinterpret_cast<object>(arguments[2]);
|
|
|
|
|
|
|
|
return reinterpret_cast<uintptr_t>
|
|
|
|
(t->m->processor->invoke(t, method, loader, specString));
|
|
|
|
}
|
|
|
|
|
2011-04-01 01:43:49 +00:00
|
|
|
bool
|
|
|
|
isInitializing(Thread* t, object c)
|
|
|
|
{
|
|
|
|
for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) {
|
|
|
|
if (s->class_ == c) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace vm {
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
Machine::Machine(System* system, Heap* heap, Finder* bootFinder,
|
|
|
|
Finder* appFinder, Processor* processor, Classpath* classpath,
|
2011-08-06 00:06:29 +00:00
|
|
|
const char** properties, unsigned propertyCount,
|
|
|
|
const char** arguments, unsigned argumentCount):
|
2007-09-10 23:33:58 +00:00
|
|
|
vtable(&javaVMVTable),
|
2007-07-06 23:50:26 +00:00
|
|
|
system(system),
|
2008-04-13 18:15:04 +00:00
|
|
|
heapClient(new (heap->allocate(sizeof(HeapClient)))
|
2008-01-13 22:05:08 +00:00
|
|
|
HeapClient(this)),
|
|
|
|
heap(heap),
|
2010-09-14 16:49:41 +00:00
|
|
|
bootFinder(bootFinder),
|
|
|
|
appFinder(appFinder),
|
2007-09-24 01:39:03 +00:00
|
|
|
processor(processor),
|
2010-09-10 21:05:29 +00:00
|
|
|
classpath(classpath),
|
2007-07-06 23:50:26 +00:00
|
|
|
rootThread(0),
|
|
|
|
exclusive(0),
|
2009-08-24 23:51:31 +00:00
|
|
|
finalizeThread(0),
|
2007-09-07 23:20:21 +00:00
|
|
|
jniReferences(0),
|
2008-11-11 15:20:49 +00:00
|
|
|
properties(properties),
|
|
|
|
propertyCount(propertyCount),
|
2011-08-06 00:06:29 +00:00
|
|
|
arguments(arguments),
|
|
|
|
argumentCount(argumentCount),
|
2007-07-06 23:50:26 +00:00
|
|
|
activeCount(0),
|
|
|
|
liveCount(0),
|
2009-08-19 20:27:03 +00:00
|
|
|
daemonCount(0),
|
2007-10-28 19:14:53 +00:00
|
|
|
fixedFootprint(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),
|
2009-08-19 20:27:03 +00:00
|
|
|
shutdownLock(0),
|
2008-01-29 15:19:15 +00:00
|
|
|
libraries(0),
|
2011-03-15 23:27:17 +00:00
|
|
|
errorLog(0),
|
2007-07-06 23:50:26 +00:00
|
|
|
types(0),
|
2010-09-14 16:49:41 +00:00
|
|
|
roots(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),
|
2011-03-26 01:11:38 +00:00
|
|
|
collecting(false),
|
2009-06-11 00:15:00 +00:00
|
|
|
triedBuiltinOnLoad(false),
|
2011-02-02 15:46:20 +00:00
|
|
|
dumpedHeapOnOOM(false),
|
support multiple sequential VM instances with bootimage build
Until now, the bootimage build hasn't supported using the Java
invocation API to create a VM, destroy it, and create another in the
same process. Ideally, we would be able to create multiple VMs
simultaneously without any interference between them. In fact, Avian
is designed to support this for the most part, but there are a few
places we use global, mutable state which prevent this from working.
Most notably, the bootimage is modified in-place at runtime, so the
best we can do without extensive changes is to clean up the bootimage
when the VM is destroyed so it's ready for later instances. Hence
this commit.
Ultimately, we can move towards a fully reentrant VM by making the
bootimage immutable, but this will require some care to avoid
performance regressions. Another challenge is our Posix signal
handlers, which currently rely on a global handle to the VM, since you
can't, to my knowledge, pass a context pointer when registering a
signal handler. Thread local variables won't necessarily help, since
a thread might attatch to more than one VM at a time.
2011-11-10 20:10:53 +00:00
|
|
|
alive(true),
|
2007-08-22 14:50:29 +00:00
|
|
|
heapPoolIndex(0)
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
2008-01-13 22:05:08 +00:00
|
|
|
heap->setClient(heapClient);
|
|
|
|
|
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
|
2009-08-19 20:27:03 +00:00
|
|
|
not system->success(system->make(&shutdownLock)) or
|
2008-11-11 15:20:49 +00:00
|
|
|
not system->success
|
2010-09-20 23:31:23 +00:00
|
|
|
(system->load(&libraries, findProperty(this, "avian.bootstrap"))))
|
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();
|
2009-08-19 20:27:03 +00:00
|
|
|
shutdownLock->dispose();
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2008-01-29 15:19:15 +00:00
|
|
|
if (libraries) {
|
|
|
|
libraries->disposeAll();
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
2007-09-07 23:20:21 +00:00
|
|
|
|
|
|
|
for (Reference* r = jniReferences; r;) {
|
2008-01-13 22:05:08 +00:00
|
|
|
Reference* tmp = r;
|
2007-09-07 23:20:21 +00:00
|
|
|
r = r->next;
|
2008-04-13 18:15:04 +00:00
|
|
|
heap->free(tmp, sizeof(*tmp));
|
2007-09-07 23:20:21 +00:00
|
|
|
}
|
2007-10-28 01:54:30 +00:00
|
|
|
|
|
|
|
for (unsigned i = 0; i < heapPoolIndex; ++i) {
|
2008-11-22 21:47:18 +00:00
|
|
|
heap->free(heapPool[i], ThreadHeapSizeInBytes);
|
2007-10-28 01:54:30 +00:00
|
|
|
}
|
|
|
|
|
2011-08-06 00:06:29 +00:00
|
|
|
heap->free(arguments, sizeof(const char*) * argumentCount);
|
|
|
|
|
2008-11-11 15:20:49 +00:00
|
|
|
heap->free(properties, sizeof(const char*) * propertyCount);
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
static_cast<HeapClient*>(heapClient)->dispose();
|
2007-10-28 19:14:53 +00:00
|
|
|
|
2008-04-13 18:15:04 +00:00
|
|
|
heap->free(this, sizeof(*this));
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
2007-07-24 01:44:20 +00:00
|
|
|
Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
2007-07-06 23:50:26 +00:00
|
|
|
vtable(&(m->jniEnvVTable)),
|
2007-09-24 01:39:03 +00:00
|
|
|
m(m),
|
2007-07-07 18:09:16 +00:00
|
|
|
parent(parent),
|
2010-12-21 02:00:23 +00:00
|
|
|
peer(0),
|
2007-07-06 23:50:26 +00:00
|
|
|
child(0),
|
2010-02-05 00:56:21 +00:00
|
|
|
waitNext(0),
|
2007-07-06 23:50:26 +00:00
|
|
|
state(NoState),
|
2007-09-07 23:20:21 +00:00
|
|
|
criticalLevel(0),
|
2007-07-07 18:09:16 +00:00
|
|
|
systemThread(0),
|
2010-02-05 00:56:21 +00:00
|
|
|
lock(0),
|
2007-07-07 18:09:16 +00:00
|
|
|
javaThread(javaThread),
|
2007-07-06 23:50:26 +00:00
|
|
|
exception(0),
|
|
|
|
heapIndex(0),
|
2007-08-23 02:24:25 +00:00
|
|
|
heapOffset(0),
|
2007-07-28 21:28:25 +00:00
|
|
|
protector(0),
|
2009-07-20 20:12:38 +00:00
|
|
|
classInitStack(0),
|
2007-10-14 01:18:25 +00:00
|
|
|
runnable(this),
|
2008-01-13 22:05:08 +00:00
|
|
|
defaultHeap(static_cast<uintptr_t*>
|
2008-11-22 21:47:18 +00:00
|
|
|
(m->heap->allocate(ThreadHeapSizeInBytes))),
|
2008-04-09 19:08:13 +00:00
|
|
|
heap(defaultHeap),
|
|
|
|
backupHeapIndex(0),
|
2010-09-14 16:49:41 +00:00
|
|
|
flags(ActiveFlag)
|
2007-10-25 22:06:05 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
void
|
|
|
|
Thread::init()
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
2009-03-04 03:05:48 +00:00
|
|
|
memset(defaultHeap, 0, ThreadHeapSizeInBytes);
|
2010-06-19 22:40:21 +00:00
|
|
|
memset(backupHeap, 0, ThreadBackupHeapSizeInBytes);
|
2009-03-04 03:05:48 +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);
|
|
|
|
}
|
|
|
|
|
2008-11-28 22:02:45 +00:00
|
|
|
BootImage* image = 0;
|
2011-09-20 22:30:30 +00:00
|
|
|
uint8_t* code = 0;
|
2008-11-28 22:02:45 +00:00
|
|
|
const char* imageFunctionName = findProperty(m, "avian.bootimage");
|
|
|
|
if (imageFunctionName) {
|
2011-09-20 22:30:30 +00:00
|
|
|
void* imagep = m->libraries->resolve(imageFunctionName);
|
|
|
|
if (imagep) {
|
|
|
|
BootImage* (*imageFunction)(unsigned*);
|
|
|
|
memcpy(&imageFunction, &imagep, BytesPerWord);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2008-11-28 22:02:45 +00:00
|
|
|
unsigned size;
|
2011-09-20 22:30:30 +00:00
|
|
|
image = imageFunction(&size);
|
|
|
|
|
|
|
|
const char* codeFunctionName = findProperty(m, "avian.codeimage");
|
|
|
|
if (codeFunctionName) {
|
|
|
|
void* codep = m->libraries->resolve(codeFunctionName);
|
|
|
|
if (codep) {
|
|
|
|
uint8_t* (*codeFunction)(unsigned*);
|
|
|
|
memcpy(&codeFunction, &codep, BytesPerWord);
|
|
|
|
|
|
|
|
code = codeFunction(&size);
|
|
|
|
}
|
|
|
|
}
|
2008-11-28 22:02:45 +00:00
|
|
|
}
|
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
|
|
|
|
m->unsafe = false;
|
|
|
|
|
2010-11-26 19:41:31 +00:00
|
|
|
enter(this, ActiveState);
|
|
|
|
|
2011-10-03 14:04:58 +00:00
|
|
|
if (image and code) {
|
2011-09-20 22:30:30 +00:00
|
|
|
m->processor->boot(this, image, code);
|
2008-11-28 22:02:45 +00:00
|
|
|
} else {
|
|
|
|
boot(this);
|
2007-11-04 21:15:28 +00:00
|
|
|
}
|
2007-07-30 23:19:05 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
setRoot(this, Machine::ByteArrayMap, makeWeakHashMap(this, 0, 0));
|
|
|
|
setRoot(this, Machine::MonitorMap, makeWeakHashMap(this, 0, 0));
|
2010-06-19 22:40:21 +00:00
|
|
|
|
2010-11-26 19:41:31 +00:00
|
|
|
setRoot(this, Machine::ClassRuntimeDataTable, makeVector(this, 0, 0));
|
|
|
|
setRoot(this, Machine::MethodRuntimeDataTable, makeVector(this, 0, 0));
|
2010-09-14 16:49:41 +00:00
|
|
|
setRoot(this, Machine::JNIMethodTable, makeVector(this, 0, 0));
|
2011-03-16 01:34:00 +00:00
|
|
|
setRoot(this, Machine::JNIFieldTable, makeVector(this, 0, 0));
|
2010-06-19 22:40:21 +00:00
|
|
|
|
2007-09-10 23:33:58 +00:00
|
|
|
m->localThread->set(this);
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-10 02:38:12 +00:00
|
|
|
|
|
|
|
javaThread = m->classpath->makeThread(this, 0);
|
|
|
|
|
|
|
|
threadPeer(this, javaThread) = reinterpret_cast<jlong>(this);
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
2007-09-10 23:33:58 +00:00
|
|
|
|
2010-02-05 00:56:21 +00:00
|
|
|
expect(this, m->system->success(m->system->make(&lock)));
|
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) {
|
2009-08-19 20:27:03 +00:00
|
|
|
turnOffTheLights(this);
|
2007-07-07 18:09:16 +00:00
|
|
|
} else {
|
2009-08-20 14:49:01 +00:00
|
|
|
threadPeer(this, javaThread) = 0;
|
2010-11-16 17:50:19 +00:00
|
|
|
|
2011-02-28 17:14:01 +00:00
|
|
|
System::Monitor* myLock = lock;
|
|
|
|
System::Thread* mySystemThread = systemThread;
|
|
|
|
|
2010-11-16 17:50:19 +00:00
|
|
|
{ ACQUIRE_RAW(this, m->stateLock);
|
|
|
|
|
|
|
|
while (flags & SystemFlag) {
|
|
|
|
m->stateLock->wait(systemThread, 0);
|
|
|
|
}
|
2011-02-28 17:14:01 +00:00
|
|
|
|
|
|
|
atomicOr(&flags, Thread::DisposeFlag);
|
2010-11-16 17:50:19 +00:00
|
|
|
|
|
|
|
enter(this, Thread::ZombieState);
|
|
|
|
}
|
2010-11-09 22:46:16 +00:00
|
|
|
|
2011-02-28 17:14:01 +00:00
|
|
|
myLock->dispose();
|
2010-11-09 22:46:16 +00:00
|
|
|
|
2011-02-28 17:14:01 +00:00
|
|
|
mySystemThread->dispose();
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Thread::dispose()
|
|
|
|
{
|
2011-02-28 17:14:01 +00:00
|
|
|
if ((flags & Thread::DisposeFlag) == 0) {
|
|
|
|
if (lock) {
|
|
|
|
lock->dispose();
|
|
|
|
}
|
2010-02-05 00:56:21 +00:00
|
|
|
|
2011-02-28 17:14:01 +00:00
|
|
|
if (systemThread) {
|
|
|
|
systemThread->dispose();
|
|
|
|
}
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
|
2008-11-22 21:47:18 +00:00
|
|
|
m->heap->free(defaultHeap, ThreadHeapSizeInBytes);
|
2007-07-17 00:23:23 +00:00
|
|
|
|
2008-01-10 01:20:36 +00:00
|
|
|
m->processor->dispose(this);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
2007-07-07 18:09:16 +00:00
|
|
|
void
|
2009-08-19 20:27:03 +00:00
|
|
|
shutDown(Thread* t)
|
2007-07-07 18:09:16 +00:00
|
|
|
{
|
2009-08-19 20:27:03 +00:00
|
|
|
ACQUIRE(t, t->m->shutdownLock);
|
2007-07-07 18:09:16 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
object hooks = root(t, Machine::ShutdownHooks);
|
2009-08-19 20:27:03 +00:00
|
|
|
PROTECT(t, hooks);
|
2007-07-07 18:09:16 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
setRoot(t, Machine::ShutdownHooks, 0);
|
2007-07-17 01:55:49 +00:00
|
|
|
|
2009-08-19 20:27:03 +00:00
|
|
|
object h = hooks;
|
|
|
|
PROTECT(t, h);
|
|
|
|
for (; h; h = pairSecond(t, h)) {
|
|
|
|
startThread(t, pairFirst(t, h));
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
|
2009-08-19 20:27:03 +00:00
|
|
|
// wait for hooks to exit
|
|
|
|
h = hooks;
|
|
|
|
for (; h; h = pairSecond(t, h)) {
|
|
|
|
while (true) {
|
|
|
|
Thread* ht = reinterpret_cast<Thread*>(threadPeer(t, pairFirst(t, h)));
|
2007-07-17 01:55:49 +00:00
|
|
|
|
2009-08-19 20:27:03 +00:00
|
|
|
{ ACQUIRE(t, t->m->stateLock);
|
2007-07-11 04:19:26 +00:00
|
|
|
|
2009-08-19 20:27:03 +00:00
|
|
|
if (ht == 0
|
|
|
|
or ht->state == Thread::ZombieState
|
|
|
|
or ht->state == Thread::JoinedState)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
ENTER(t, Thread::IdleState);
|
|
|
|
t->m->stateLock->wait(t->systemThread, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-08-24 23:51:31 +00:00
|
|
|
|
|
|
|
// tell finalize thread to exit and wait for it to do so
|
|
|
|
{ ACQUIRE(t, t->m->stateLock);
|
|
|
|
Thread* finalizeThread = t->m->finalizeThread;
|
|
|
|
if (finalizeThread) {
|
|
|
|
t->m->finalizeThread = 0;
|
|
|
|
t->m->stateLock->notifyAll(t->systemThread);
|
|
|
|
|
|
|
|
while (finalizeThread->state != Thread::ZombieState
|
|
|
|
and finalizeThread->state != Thread::JoinedState)
|
|
|
|
{
|
|
|
|
ENTER(t, Thread::IdleState);
|
|
|
|
t->m->stateLock->wait(t->systemThread, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
support multiple sequential VM instances with bootimage build
Until now, the bootimage build hasn't supported using the Java
invocation API to create a VM, destroy it, and create another in the
same process. Ideally, we would be able to create multiple VMs
simultaneously without any interference between them. In fact, Avian
is designed to support this for the most part, but there are a few
places we use global, mutable state which prevent this from working.
Most notably, the bootimage is modified in-place at runtime, so the
best we can do without extensive changes is to clean up the bootimage
when the VM is destroyed so it's ready for later instances. Hence
this commit.
Ultimately, we can move towards a fully reentrant VM by making the
bootimage immutable, but this will require some care to avoid
performance regressions. Another challenge is our Posix signal
handlers, which currently rely on a global handle to the VM, since you
can't, to my knowledge, pass a context pointer when registering a
signal handler. Thread local variables won't necessarily help, since
a thread might attatch to more than one VM at a time.
2011-11-10 20:10:53 +00:00
|
|
|
|
|
|
|
// interrupt daemon threads and tell them to die
|
|
|
|
|
|
|
|
// todo: be more aggressive about killing daemon threads, e.g. at
|
|
|
|
// any GC point, not just at waits/sleeps
|
|
|
|
{ ACQUIRE(t, t->m->stateLock);
|
|
|
|
|
|
|
|
t->m->alive = false;
|
|
|
|
|
|
|
|
visitAll(t, t->m->rootThread, interruptDaemon);
|
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
|
2009-11-28 22:01:54 +00:00
|
|
|
#ifdef USE_ATOMIC_OPERATIONS
|
|
|
|
# define INCREMENT atomicIncrement
|
|
|
|
# define ACQUIRE_LOCK ACQUIRE_RAW(t, t->m->stateLock)
|
2009-11-30 15:38:16 +00:00
|
|
|
# define STORE_LOAD_MEMORY_BARRIER storeLoadMemoryBarrier()
|
2009-11-28 22:01:54 +00:00
|
|
|
#else
|
|
|
|
# define INCREMENT(pointer, value) *(pointer) += value;
|
|
|
|
# define ACQUIRE_LOCK
|
2009-11-30 15:38:16 +00:00
|
|
|
# define STORE_LOAD_MEMORY_BARRIER
|
2009-11-28 22:01:54 +00:00
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
ACQUIRE_RAW(t, t->m->stateLock);
|
2009-11-28 22:01:54 +00:00
|
|
|
#endif // not USE_ATOMIC_OPERATIONS
|
2007-07-06 23:50:26 +00:00
|
|
|
|
|
|
|
switch (s) {
|
|
|
|
case Thread::ExclusiveState: {
|
2009-11-28 22:01:54 +00:00
|
|
|
ACQUIRE_LOCK;
|
|
|
|
|
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);
|
2009-11-29 23:53:05 +00:00
|
|
|
t->m->stateLock->wait(t->systemThread, 0);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
2008-01-18 01:47:32 +00:00
|
|
|
switch (t->state) {
|
|
|
|
case Thread::ActiveState: break;
|
|
|
|
|
|
|
|
case Thread::IdleState: {
|
2009-11-28 22:01:54 +00:00
|
|
|
INCREMENT(&(t->m->activeCount), 1);
|
2008-01-18 01:47:32 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
t->state = Thread::ExclusiveState;
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->exclusive = t;
|
2009-11-28 22:01:54 +00:00
|
|
|
|
2009-11-30 15:38:16 +00:00
|
|
|
STORE_LOAD_MEMORY_BARRIER;
|
2009-11-28 22:01:54 +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:
|
2010-09-14 16:49:41 +00:00
|
|
|
if (LIKELY(t->state == Thread::ActiveState)) {
|
2009-11-28 22:01:54 +00:00
|
|
|
// fast path
|
|
|
|
assert(t, t->m->activeCount > 0);
|
|
|
|
INCREMENT(&(t->m->activeCount), -1);
|
|
|
|
|
|
|
|
t->state = s;
|
|
|
|
|
|
|
|
if (t->m->exclusive) {
|
|
|
|
ACQUIRE_LOCK;
|
|
|
|
|
|
|
|
t->m->stateLock->notifyAll(t->systemThread);
|
|
|
|
}
|
2010-09-10 21:05:29 +00:00
|
|
|
|
2009-11-28 22:01:54 +00:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
// fall through to slow path
|
|
|
|
}
|
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
case Thread::ZombieState: {
|
2009-11-28 22:01:54 +00:00
|
|
|
ACQUIRE_LOCK;
|
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
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);
|
2009-11-28 22:01:54 +00:00
|
|
|
INCREMENT(&(t->m->activeCount), -1);
|
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;
|
2009-08-19 20:27:03 +00:00
|
|
|
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-10 02:38:12 +00:00
|
|
|
if (t->flags & Thread::DaemonFlag) {
|
2009-08-19 20:27:03 +00:00
|
|
|
-- t->m->daemonCount;
|
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
2010-12-21 02:00:23 +00:00
|
|
|
|
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;
|
|
|
|
|
2009-11-28 22:01:54 +00:00
|
|
|
case Thread::ActiveState:
|
2010-09-14 16:49:41 +00:00
|
|
|
if (LIKELY(t->state == Thread::IdleState and t->m->exclusive == 0)) {
|
2009-11-28 22:01:54 +00:00
|
|
|
// fast path
|
|
|
|
INCREMENT(&(t->m->activeCount), 1);
|
2009-11-28 22:24:02 +00:00
|
|
|
|
2009-11-28 22:35:15 +00:00
|
|
|
t->state = s;
|
|
|
|
|
2009-11-28 22:24:02 +00:00
|
|
|
if (t->m->exclusive) {
|
2009-11-28 22:35:15 +00:00
|
|
|
// another thread has entered the exclusive state, so we
|
|
|
|
// return to idle and use the slow path to become active
|
|
|
|
enter(t, Thread::IdleState);
|
2009-11-28 22:24:02 +00:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{ ACQUIRE_LOCK;
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2009-11-28 22:01:54 +00:00
|
|
|
switch (t->state) {
|
|
|
|
case Thread::ExclusiveState: {
|
|
|
|
assert(t, t->m->exclusive == t);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2009-11-28 22:01:54 +00:00
|
|
|
t->state = s;
|
|
|
|
t->m->exclusive = 0;
|
|
|
|
|
|
|
|
t->m->stateLock->notifyAll(t->systemThread);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case Thread::NoState:
|
|
|
|
case Thread::IdleState: {
|
|
|
|
while (t->m->exclusive) {
|
|
|
|
t->m->stateLock->wait(t->systemThread, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
INCREMENT(&(t->m->activeCount), 1);
|
|
|
|
if (t->state == Thread::NoState) {
|
|
|
|
++ t->m->liveCount;
|
|
|
|
}
|
|
|
|
t->state = s;
|
|
|
|
} break;
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2009-11-28 22:01:54 +00:00
|
|
|
default: abort(t);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case Thread::ExitState: {
|
2009-11-28 22:01:54 +00:00
|
|
|
ACQUIRE_LOCK;
|
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
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-11-27 22:23:00 +00:00
|
|
|
|
|
|
|
t->m->stateLock->notifyAll(t->systemThread);
|
2007-07-06 23:50:26 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case Thread::ActiveState: break;
|
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
2007-07-18 01:33:00 +00:00
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
assert(t, t->m->activeCount > 0);
|
2009-11-28 22:01:54 +00:00
|
|
|
INCREMENT(&(t->m->activeCount), -1);
|
2007-07-18 01:33:00 +00:00
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
t->state = s;
|
|
|
|
|
2009-08-19 20:27:03 +00:00
|
|
|
while (t->m->liveCount - t->m->daemonCount > 1) {
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->stateLock->wait(t->systemThread, 0);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
2008-01-10 01:20:36 +00:00
|
|
|
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask)
|
|
|
|
{
|
|
|
|
return allocate3
|
2008-01-13 22:05:08 +00:00
|
|
|
(t, t->m->heap,
|
2008-11-22 21:47:18 +00:00
|
|
|
ceiling(sizeInBytes, BytesPerWord) > ThreadHeapSizeInWords ?
|
2008-01-10 01:20:36 +00:00
|
|
|
Machine::FixedAllocation : Machine::MovableAllocation,
|
2008-04-13 18:15:04 +00:00
|
|
|
sizeInBytes, objectMask);
|
2008-01-10 01:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
2008-04-13 18:15:04 +00:00
|
|
|
unsigned sizeInBytes, bool objectMask)
|
2007-10-28 01:54:30 +00:00
|
|
|
{
|
2010-09-14 16:49:41 +00:00
|
|
|
if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) {
|
2008-04-09 19:08:13 +00:00
|
|
|
expect(t, t->backupHeapIndex + ceiling(sizeInBytes, BytesPerWord)
|
2010-06-19 22:40:21 +00:00
|
|
|
<= ThreadBackupHeapSizeInWords);
|
2008-04-09 19:08:13 +00:00
|
|
|
|
|
|
|
object o = reinterpret_cast<object>(t->backupHeap + t->backupHeapIndex);
|
|
|
|
t->backupHeapIndex += ceiling(sizeInBytes, BytesPerWord);
|
|
|
|
cast<object>(o, 0) = 0;
|
|
|
|
return o;
|
2010-09-14 16:49:41 +00:00
|
|
|
} else if (UNLIKELY(t->flags & Thread::TracingFlag)) {
|
2008-04-21 22:36:13 +00:00
|
|
|
expect(t, t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
2008-11-22 21:47:18 +00:00
|
|
|
<= ThreadHeapSizeInWords);
|
2008-04-21 22:36:13 +00:00
|
|
|
return allocateSmall(t, sizeInBytes);
|
2008-04-09 19:08:13 +00:00
|
|
|
}
|
|
|
|
|
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);
|
2009-07-16 17:51:35 +00:00
|
|
|
|
|
|
|
while (t->m->exclusive) {
|
|
|
|
t->m->stateLock->wait(t->systemThread, 0);
|
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
2008-11-23 18:48:39 +00:00
|
|
|
|
2009-07-18 01:37:46 +00:00
|
|
|
do {
|
|
|
|
switch (type) {
|
|
|
|
case Machine::MovableAllocation:
|
|
|
|
if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
|
|
|
> ThreadHeapSizeInWords)
|
|
|
|
{
|
|
|
|
t->heap = 0;
|
2010-12-27 22:55:23 +00:00
|
|
|
if ((not t->m->heap->limitExceeded())
|
|
|
|
and t->m->heapPoolIndex < ThreadHeapPoolSize)
|
|
|
|
{
|
2009-07-18 01:37:46 +00:00
|
|
|
t->heap = static_cast<uintptr_t*>
|
|
|
|
(t->m->heap->tryAllocate(ThreadHeapSizeInBytes));
|
2009-03-04 03:05:48 +00:00
|
|
|
|
2009-07-18 01:37:46 +00:00
|
|
|
if (t->heap) {
|
|
|
|
memset(t->heap, 0, ThreadHeapSizeInBytes);
|
2009-03-04 03:05:48 +00:00
|
|
|
|
2009-07-18 01:37:46 +00:00
|
|
|
t->m->heapPool[t->m->heapPoolIndex++] = t->heap;
|
|
|
|
t->heapOffset += t->heapIndex;
|
|
|
|
t->heapIndex = 0;
|
|
|
|
}
|
2008-11-23 18:48:39 +00:00
|
|
|
}
|
2007-08-22 14:50:29 +00:00
|
|
|
}
|
2009-07-18 01:37:46 +00:00
|
|
|
break;
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2009-07-18 01:37:46 +00:00
|
|
|
case Machine::FixedAllocation:
|
|
|
|
if (t->m->fixedFootprint + sizeInBytes > FixedFootprintThresholdInBytes)
|
|
|
|
{
|
|
|
|
t->heap = 0;
|
|
|
|
}
|
|
|
|
break;
|
2008-11-23 18:48:39 +00:00
|
|
|
|
2009-07-18 01:37:46 +00:00
|
|
|
case Machine::ImmortalAllocation:
|
|
|
|
break;
|
|
|
|
}
|
2007-08-22 14:50:29 +00:00
|
|
|
|
2009-07-18 01:37:46 +00:00
|
|
|
if (t->heap == 0) {
|
|
|
|
// fprintf(stderr, "gc");
|
|
|
|
// vmPrintTrace(t);
|
|
|
|
collect(t, Heap::MinorCollection);
|
|
|
|
}
|
2010-12-27 22:55:23 +00:00
|
|
|
|
|
|
|
if (t->m->heap->limitExceeded()) {
|
|
|
|
throw_(t, root(t, Machine::OutOfMemoryError));
|
|
|
|
}
|
2009-07-18 01:37:46 +00:00
|
|
|
} while (type == Machine::MovableAllocation
|
|
|
|
and t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
|
|
|
> ThreadHeapSizeInWords);
|
2008-01-10 01:20:36 +00:00
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case Machine::MovableAllocation: {
|
|
|
|
return allocateSmall(t, sizeInBytes);
|
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2008-01-10 01:20:36 +00:00
|
|
|
case Machine::FixedAllocation: {
|
2007-10-28 19:14:53 +00:00
|
|
|
unsigned total;
|
|
|
|
object o = static_cast<object>
|
|
|
|
(t->m->heap->allocateFixed
|
2008-01-14 23:37:24 +00:00
|
|
|
(allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total));
|
2007-10-28 19:14:53 +00:00
|
|
|
|
2009-03-04 03:05:48 +00:00
|
|
|
memset(o, 0, sizeInBytes);
|
|
|
|
|
2011-02-14 18:47:59 +00:00
|
|
|
alias(o, 0) = FixedMark;
|
2007-10-28 19:14:53 +00:00
|
|
|
|
|
|
|
t->m->fixedFootprint += total;
|
|
|
|
|
|
|
|
return o;
|
2008-01-10 01:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case Machine::ImmortalAllocation: {
|
|
|
|
unsigned total;
|
|
|
|
object o = static_cast<object>
|
2008-11-29 02:31:06 +00:00
|
|
|
(t->m->heap->allocateImmortalFixed
|
2008-04-13 18:15:04 +00:00
|
|
|
(allocator, ceiling(sizeInBytes, BytesPerWord), objectMask, &total));
|
2008-01-10 01:20:36 +00:00
|
|
|
|
2009-03-04 03:05:48 +00:00
|
|
|
memset(o, 0, sizeInBytes);
|
|
|
|
|
2011-02-14 18:47:59 +00:00
|
|
|
alias(o, 0) = FixedMark;
|
2008-01-10 01:20:36 +00:00
|
|
|
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
|
|
|
default: abort(t);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-22 00:57:55 +00:00
|
|
|
object
|
|
|
|
makeNewGeneral(Thread* t, object class_)
|
|
|
|
{
|
|
|
|
assert(t, t->state == Thread::ActiveState);
|
|
|
|
|
2009-08-10 23:35:44 +00:00
|
|
|
PROTECT(t, class_);
|
|
|
|
|
2009-07-22 00:57:55 +00:00
|
|
|
object instance = makeNew(t, class_);
|
|
|
|
PROTECT(t, instance);
|
|
|
|
|
|
|
|
if (classVmFlags(t, class_) & WeakReferenceFlag) {
|
|
|
|
ACQUIRE(t, t->m->referenceLock);
|
|
|
|
|
|
|
|
jreferenceVmNext(t, instance) = t->m->weakReferences;
|
|
|
|
t->m->weakReferences = instance;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (classVmFlags(t, class_) & HasFinalizerFlag) {
|
2009-08-24 23:51:31 +00:00
|
|
|
addFinalizer(t, instance, 0);
|
2009-07-22 00:57:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2011-01-27 18:54:41 +00:00
|
|
|
void
|
|
|
|
popResources(Thread* t)
|
2010-12-27 22:55:23 +00:00
|
|
|
{
|
2011-01-27 18:54:41 +00:00
|
|
|
while (t->resource != t->checkpoint->resource) {
|
2010-12-27 22:55:23 +00:00
|
|
|
Thread::Resource* r = t->resource;
|
|
|
|
t->resource = r->next;
|
|
|
|
r->release();
|
|
|
|
}
|
|
|
|
|
2011-01-27 18:54:41 +00:00
|
|
|
t->protector = t->checkpoint->protector;
|
2010-12-27 22:55:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeByteArray(Thread* t, const char* format, va_list a)
|
|
|
|
{
|
2011-07-10 00:00:19 +00:00
|
|
|
int size = 256;
|
|
|
|
while (true) {
|
|
|
|
THREAD_RUNTIME_ARRAY(t, char, buffer, size);
|
2010-12-27 22:55:23 +00:00
|
|
|
|
2011-07-10 00:00:19 +00:00
|
|
|
int r = vm::vsnprintf(RUNTIME_ARRAY_BODY(buffer), size - 1, format, a);
|
|
|
|
if (r >= 0 and r < size - 1) {
|
|
|
|
object s = makeByteArray(t, strlen(RUNTIME_ARRAY_BODY(buffer)) + 1);
|
|
|
|
memcpy(&byteArrayBody(t, s, 0), RUNTIME_ARRAY_BODY(buffer),
|
|
|
|
byteArrayLength(t, s));
|
|
|
|
return s;
|
|
|
|
} else {
|
|
|
|
size *= 2;
|
|
|
|
}
|
|
|
|
}
|
2010-12-27 22:55:23 +00:00
|
|
|
}
|
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
object
|
|
|
|
makeByteArray(Thread* t, const char* format, ...)
|
|
|
|
{
|
|
|
|
va_list a;
|
|
|
|
va_start(a, format);
|
2010-12-27 22:55:23 +00:00
|
|
|
object s = makeByteArray(t, format, a);
|
2007-07-06 23:50:26 +00:00
|
|
|
va_end(a);
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeString(Thread* t, const char* format, ...)
|
|
|
|
{
|
|
|
|
va_list a;
|
|
|
|
va_start(a, format);
|
2010-12-27 22:55:23 +00:00
|
|
|
object s = makeByteArray(t, format, a);
|
2007-07-06 23:50:26 +00:00
|
|
|
va_end(a);
|
|
|
|
|
2010-09-10 21:05:29 +00:00
|
|
|
return t->m->classpath->makeString(t, s, 0, byteArrayLength(t, s) - 1);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
2010-04-20 16:03:07 +00:00
|
|
|
int
|
2010-09-10 21:05:29 +00:00
|
|
|
stringUTFLength(Thread* t, object string, unsigned start, unsigned length)
|
|
|
|
{
|
|
|
|
unsigned result = 0;
|
2010-04-20 16:03:07 +00:00
|
|
|
|
2010-09-10 21:05:29 +00:00
|
|
|
if (length) {
|
2010-04-20 16:03:07 +00:00
|
|
|
object data = stringData(t, string);
|
2010-09-14 16:49:41 +00:00
|
|
|
if (objectClass(t, data) == type(t, Machine::ByteArrayType)) {
|
2010-09-10 21:05:29 +00:00
|
|
|
result = length;
|
2010-04-20 16:03:07 +00:00
|
|
|
} else {
|
2010-09-10 21:05:29 +00:00
|
|
|
for (unsigned i = 0; i < length; ++i) {
|
|
|
|
uint16_t c = charArrayBody
|
|
|
|
(t, data, stringOffset(t, string) + start + i);
|
|
|
|
if (c == 0) result += 1; // null char (was 2 bytes in Java)
|
|
|
|
else if (c < 0x80) result += 1; // ASCII char
|
|
|
|
else if (c < 0x800) result += 2; // two-byte char
|
|
|
|
else result += 3; // three-byte char
|
2010-04-20 16:03:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-10 21:05:29 +00:00
|
|
|
return result;
|
2010-04-20 16:03:07 +00:00
|
|
|
}
|
|
|
|
|
2007-07-08 01:06:32 +00:00
|
|
|
void
|
2010-09-10 21:05:29 +00:00
|
|
|
stringChars(Thread* t, object string, unsigned start, unsigned length,
|
|
|
|
char* chars)
|
2007-07-08 01:06:32 +00:00
|
|
|
{
|
2010-09-10 21:05:29 +00:00
|
|
|
if (length) {
|
2009-08-13 15:17:05 +00:00
|
|
|
object data = stringData(t, string);
|
2010-09-14 16:49:41 +00:00
|
|
|
if (objectClass(t, data) == type(t, Machine::ByteArrayType)) {
|
2009-08-13 15:17:05 +00:00
|
|
|
memcpy(chars,
|
2010-09-10 21:05:29 +00:00
|
|
|
&byteArrayBody(t, data, stringOffset(t, string) + start),
|
|
|
|
length);
|
2009-08-13 15:17:05 +00:00
|
|
|
} else {
|
2010-09-10 21:05:29 +00:00
|
|
|
for (unsigned i = 0; i < length; ++i) {
|
|
|
|
chars[i] = charArrayBody(t, data, stringOffset(t, string) + start + i);
|
2009-08-13 15:17:05 +00:00
|
|
|
}
|
2007-07-08 01:06:32 +00:00
|
|
|
}
|
|
|
|
}
|
2010-09-10 21:05:29 +00:00
|
|
|
chars[length] = 0;
|
2007-07-08 01:06:32 +00:00
|
|
|
}
|
|
|
|
|
2008-04-01 23:24:43 +00:00
|
|
|
void
|
2010-09-10 21:05:29 +00:00
|
|
|
stringChars(Thread* t, object string, unsigned start, unsigned length,
|
|
|
|
uint16_t* chars)
|
2008-04-01 23:24:43 +00:00
|
|
|
{
|
2010-09-10 21:05:29 +00:00
|
|
|
if (length) {
|
2009-08-13 15:17:05 +00:00
|
|
|
object data = stringData(t, string);
|
2010-09-14 16:49:41 +00:00
|
|
|
if (objectClass(t, data) == type(t, Machine::ByteArrayType)) {
|
2010-09-10 21:05:29 +00:00
|
|
|
for (unsigned i = 0; i < length; ++i) {
|
|
|
|
chars[i] = byteArrayBody(t, data, stringOffset(t, string) + start + i);
|
2009-08-13 15:17:05 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
memcpy(chars,
|
2010-09-10 21:05:29 +00:00
|
|
|
&charArrayBody(t, data, stringOffset(t, string) + start),
|
|
|
|
length * sizeof(uint16_t));
|
2008-04-01 23:24:43 +00:00
|
|
|
}
|
|
|
|
}
|
2010-09-10 21:05:29 +00:00
|
|
|
chars[length] = 0;
|
2008-04-01 23:24:43 +00:00
|
|
|
}
|
|
|
|
|
2010-04-20 16:03:07 +00:00
|
|
|
void
|
2010-09-10 21:05:29 +00:00
|
|
|
stringUTFChars(Thread* t, object string, unsigned start, unsigned length,
|
|
|
|
char* chars, unsigned charsLength UNUSED)
|
2010-04-20 16:03:07 +00:00
|
|
|
{
|
2010-09-10 21:05:29 +00:00
|
|
|
assert(t, static_cast<unsigned>
|
|
|
|
(stringUTFLength(t, string, start, length)) == charsLength);
|
2010-04-20 16:03:07 +00:00
|
|
|
|
2010-09-10 21:05:29 +00:00
|
|
|
if (length) {
|
2010-04-20 16:03:07 +00:00
|
|
|
object data = stringData(t, string);
|
2010-09-14 16:49:41 +00:00
|
|
|
if (objectClass(t, data) == type(t, Machine::ByteArrayType)) {
|
2010-04-20 16:03:07 +00:00
|
|
|
memcpy(chars,
|
2010-09-10 21:05:29 +00:00
|
|
|
&byteArrayBody(t, data, stringOffset(t, string) + start),
|
|
|
|
length);
|
|
|
|
chars[length] = 0;
|
2010-04-20 16:03:07 +00:00
|
|
|
} else {
|
|
|
|
int j = 0;
|
2010-09-10 21:05:29 +00:00
|
|
|
for (unsigned i = 0; i < length; ++i) {
|
|
|
|
uint16_t c = charArrayBody
|
|
|
|
(t, data, stringOffset(t, string) + start + i);
|
2010-04-20 16:03:07 +00:00
|
|
|
if(!c) { // null char
|
|
|
|
chars[j++] = 0;
|
|
|
|
} else if (c < 0x80) { // ASCII char
|
|
|
|
chars[j++] = static_cast<char>(c);
|
|
|
|
} else if (c < 0x800) { // two-byte char
|
|
|
|
chars[j++] = static_cast<char>(0x0c0 | (c >> 6));
|
|
|
|
chars[j++] = static_cast<char>(0x080 | (c & 0x03f));
|
|
|
|
} else { // three-byte char
|
|
|
|
chars[j++] = static_cast<char>(0x0e0 | ((c >> 12) & 0x0f));
|
|
|
|
chars[j++] = static_cast<char>(0x080 | ((c >> 6) & 0x03f));
|
|
|
|
chars[j++] = static_cast<char>(0x080 | (c & 0x03f));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
chars[j] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
uint64_t
|
|
|
|
resolveBootstrap(Thread* t, uintptr_t* arguments)
|
|
|
|
{
|
|
|
|
object name = reinterpret_cast<object>(arguments[0]);
|
|
|
|
|
|
|
|
resolveSystemClass(t, root(t, Machine::BootLoader), name);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2007-07-24 01:44:20 +00:00
|
|
|
bool
|
|
|
|
isAssignableFrom(Thread* t, object a, object b)
|
|
|
|
{
|
2010-09-14 16:49:41 +00:00
|
|
|
assert(t, a);
|
|
|
|
assert(t, b);
|
|
|
|
|
2007-11-05 14:28:46 +00:00
|
|
|
if (a == b) return true;
|
|
|
|
|
|
|
|
if (classFlags(t, a) & ACC_INTERFACE) {
|
2007-11-04 23:10:33 +00:00
|
|
|
if (classVmFlags(t, b) & BootstrapFlag) {
|
2010-12-27 22:55:23 +00:00
|
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(className(t, b)) };
|
|
|
|
|
|
|
|
if (run(t, resolveBootstrap, arguments) == 0) {
|
2007-11-05 16:08:08 +00:00
|
|
|
t->exception = 0;
|
|
|
|
return false;
|
|
|
|
}
|
2007-11-04 23:10:33 +00:00
|
|
|
}
|
2007-08-20 02:57:32 +00:00
|
|
|
|
2011-04-10 03:09:59 +00:00
|
|
|
object itable = classInterfaceTable(t, b);
|
|
|
|
if (itable) {
|
|
|
|
unsigned stride = (classFlags(t, b) & ACC_INTERFACE) ? 1 : 2;
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, itable); i += stride) {
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-07-05 20:21:13 +00:00
|
|
|
bool
|
2007-07-24 01:44:20 +00:00
|
|
|
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_)
|
|
|
|
{
|
2011-07-18 01:51:48 +00:00
|
|
|
if (classMethodTable(t, class_)) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, classMethodTable(t, class_)); ++i)
|
2007-07-28 16:10:13 +00:00
|
|
|
{
|
2011-07-18 01:51:48 +00:00
|
|
|
object o = arrayBody(t, classMethodTable(t, class_), i);
|
|
|
|
|
support multiple sequential VM instances with bootimage build
Until now, the bootimage build hasn't supported using the Java
invocation API to create a VM, destroy it, and create another in the
same process. Ideally, we would be able to create multiple VMs
simultaneously without any interference between them. In fact, Avian
is designed to support this for the most part, but there are a few
places we use global, mutable state which prevent this from working.
Most notably, the bootimage is modified in-place at runtime, so the
best we can do without extensive changes is to clean up the bootimage
when the VM is destroyed so it's ready for later instances. Hence
this commit.
Ultimately, we can move towards a fully reentrant VM by making the
bootimage immutable, but this will require some care to avoid
performance regressions. Another challenge is our Posix signal
handlers, which currently rely on a global handle to the VM, since you
can't, to my knowledge, pass a context pointer when registering a
signal handler. Thread local variables won't necessarily help, since
a thread might attatch to more than one VM at a time.
2011-11-10 20:10:53 +00:00
|
|
|
if (methodVmFlags(t, o) & ClassInitFlag) {
|
2011-07-18 01:51:48 +00:00
|
|
|
return o;
|
|
|
|
}
|
|
|
|
}
|
2007-07-28 16:10:13 +00:00
|
|
|
}
|
2011-04-01 01:43:49 +00:00
|
|
|
return 0;
|
2007-07-28 16:10:13 +00:00
|
|
|
}
|
|
|
|
|
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
|
2011-03-18 03:42:15 +00:00
|
|
|
parseClass(Thread* t, object loader, const uint8_t* data, unsigned size,
|
|
|
|
Machine::Type throwType)
|
2007-07-30 23:19:05 +00:00
|
|
|
{
|
2009-08-10 13:56:16 +00:00
|
|
|
PROTECT(t, loader);
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
class Client: public Stream::Client {
|
2007-07-30 23:19:05 +00:00
|
|
|
public:
|
|
|
|
Client(Thread* t): t(t) { }
|
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
virtual void NO_RETURN handleError() {
|
2009-08-27 00:26:44 +00:00
|
|
|
vm::abort(t);
|
2007-07-30 23:19:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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, // fixed size
|
|
|
|
0, // array size
|
2009-08-18 20:26:28 +00:00
|
|
|
0, // array dimensions
|
2010-11-26 19:41:31 +00:00
|
|
|
0, // runtime data index
|
2007-07-30 23:19:05 +00:00
|
|
|
0, // object mask
|
2009-08-18 20:26:28 +00:00
|
|
|
referenceName
|
|
|
|
(t, singletonObject(t, pool, name - 1)),
|
2009-09-19 00:01:54 +00:00
|
|
|
0, // source file
|
2007-07-30 23:19:05 +00:00
|
|
|
0, // super
|
|
|
|
0, // interfaces
|
|
|
|
0, // vtable
|
|
|
|
0, // fields
|
|
|
|
0, // methods
|
2009-09-19 00:01:54 +00:00
|
|
|
0, // addendum
|
2007-07-30 23:19:05 +00:00
|
|
|
0, // static table
|
2009-08-10 13:56:16 +00:00
|
|
|
loader,
|
2011-04-01 01:16:57 +00:00
|
|
|
0, // source
|
2009-03-04 03:05:48 +00:00
|
|
|
0);// vtable length
|
2007-07-30 23:19:05 +00:00
|
|
|
PROTECT(t, class_);
|
|
|
|
|
|
|
|
unsigned super = s.read2();
|
|
|
|
if (super) {
|
2009-08-18 20:26:28 +00:00
|
|
|
object sc = resolveClass
|
2011-03-18 03:42:15 +00:00
|
|
|
(t, loader, referenceName(t, singletonObject(t, pool, super - 1)),
|
|
|
|
true, throwType);
|
2007-07-30 23:19:05 +00:00
|
|
|
|
2007-10-22 17:22:30 +00:00
|
|
|
set(t, class_, ClassSuper, sc);
|
2007-07-30 23:19:05 +00:00
|
|
|
|
|
|
|
classVmFlags(t, class_)
|
2009-07-22 00:57:55 +00:00
|
|
|
|= (classVmFlags(t, sc)
|
2011-04-01 01:43:49 +00:00
|
|
|
& (ReferenceFlag | WeakReferenceFlag | HasFinalizerFlag
|
|
|
|
| NeedInitFlag));
|
2007-07-30 23:19:05 +00:00
|
|
|
}
|
|
|
|
|
2011-03-18 03:42:15 +00:00
|
|
|
parseInterfaceTable(t, s, class_, pool, throwType);
|
2007-07-30 23:19:05 +00:00
|
|
|
|
|
|
|
parseFieldTable(t, s, class_, pool);
|
|
|
|
|
|
|
|
parseMethodTable(t, s, class_, pool);
|
|
|
|
|
2009-08-27 22:26:25 +00:00
|
|
|
parseAttributeTable(t, s, class_, pool);
|
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
object vtable = classVirtualTable(t, class_);
|
|
|
|
unsigned vtableLength = (vtable ? arrayLength(t, vtable) : 0);
|
|
|
|
|
|
|
|
object real = t->m->processor->makeClass
|
|
|
|
(t,
|
|
|
|
classFlags(t, class_),
|
|
|
|
classVmFlags(t, class_),
|
|
|
|
classFixedSize(t, class_),
|
|
|
|
classArrayElementSize(t, class_),
|
2009-08-18 20:26:28 +00:00
|
|
|
classArrayDimensions(t, class_),
|
2007-11-05 21:40:17 +00:00
|
|
|
classObjectMask(t, class_),
|
|
|
|
className(t, class_),
|
2009-08-27 22:26:25 +00:00
|
|
|
classSourceFile(t, class_),
|
2007-11-05 21:40:17 +00:00
|
|
|
classSuper(t, class_),
|
|
|
|
classInterfaceTable(t, class_),
|
|
|
|
classVirtualTable(t, class_),
|
|
|
|
classFieldTable(t, class_),
|
|
|
|
classMethodTable(t, class_),
|
2009-09-19 00:01:54 +00:00
|
|
|
classAddendum(t, class_),
|
2007-11-05 21:40:17 +00:00
|
|
|
classStaticTable(t, class_),
|
|
|
|
classLoader(t, class_),
|
|
|
|
vtableLength);
|
|
|
|
|
2009-06-04 23:21:42 +00:00
|
|
|
PROTECT(t, real);
|
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
t->m->processor->initVtable(t, real);
|
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
updateClassTables(t, real, class_);
|
|
|
|
|
2011-08-30 01:00:17 +00:00
|
|
|
if (root(t, Machine::PoolMap)) {
|
|
|
|
object bootstrapClass = hashMapFind
|
|
|
|
(t, root(t, Machine::BootstrapClassMap), className(t, class_),
|
|
|
|
byteArrayHash, byteArrayEqual);
|
|
|
|
|
|
|
|
hashMapInsert
|
|
|
|
(t, root(t, Machine::PoolMap), bootstrapClass ? bootstrapClass : real,
|
|
|
|
pool, objectHash);
|
|
|
|
}
|
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
return real;
|
2007-07-30 23:19:05 +00:00
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
object
|
2011-03-18 03:42:15 +00:00
|
|
|
resolveSystemClass(Thread* t, object loader, object spec, bool throw_,
|
|
|
|
Machine::Type throwType)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
2010-09-14 16:49:41 +00:00
|
|
|
PROTECT(t, loader);
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, spec);
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
ACQUIRE(t, t->m->classLock);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2008-12-02 02:38:00 +00:00
|
|
|
object class_ = hashMapFind
|
2010-09-22 19:58:46 +00:00
|
|
|
(t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual);
|
2008-12-02 02:38:00 +00:00
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
if (class_ == 0) {
|
2011-04-01 01:16:57 +00:00
|
|
|
PROTECT(t, class_);
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
if (classLoaderParent(t, loader)) {
|
|
|
|
class_ = resolveSystemClass
|
|
|
|
(t, classLoaderParent(t, loader), spec, false);
|
|
|
|
if (class_) {
|
|
|
|
return class_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
if (byteArrayBody(t, spec, 0) == '[') {
|
2011-03-18 03:42:15 +00:00
|
|
|
class_ = resolveArrayClass(t, loader, spec, throw_, throwType);
|
2007-07-14 17:31:01 +00:00
|
|
|
} else {
|
2010-12-27 22:55:23 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, file, byteArrayLength(t, spec) + 6);
|
2009-08-27 00:26:44 +00:00
|
|
|
memcpy(RUNTIME_ARRAY_BODY(file),
|
|
|
|
&byteArrayBody(t, spec, 0),
|
|
|
|
byteArrayLength(t, spec) - 1);
|
|
|
|
memcpy(RUNTIME_ARRAY_BODY(file) + byteArrayLength(t, spec) - 1,
|
|
|
|
".class",
|
|
|
|
7);
|
2007-08-10 23:45:47 +00:00
|
|
|
|
2010-09-22 19:58:46 +00:00
|
|
|
System::Region* region = static_cast<Finder*>
|
|
|
|
(systemClassLoaderFinder(t, loader))->find
|
2010-09-14 16:49:41 +00:00
|
|
|
(RUNTIME_ARRAY_BODY(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
|
|
|
}
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
{ THREAD_RESOURCE(t, System::Region*, region, region->dispose());
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
// parse class file
|
2011-03-18 03:42:15 +00:00
|
|
|
class_ = parseClass
|
|
|
|
(t, loader, region->start(), region->length(), throwType);
|
2010-12-27 22:55:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Verbose) {
|
|
|
|
fprintf(stderr, "done parsing %s: %p\n",
|
|
|
|
&byteArrayBody(t, spec, 0),
|
|
|
|
class_);
|
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2011-04-01 01:16:57 +00:00
|
|
|
{ const char* source = static_cast<Finder*>
|
|
|
|
(systemClassLoaderFinder(t, loader))->sourceUrl
|
|
|
|
(RUNTIME_ARRAY_BODY(file));
|
|
|
|
|
|
|
|
if (source) {
|
|
|
|
unsigned length = strlen(source);
|
|
|
|
object array = makeByteArray(t, length + 1);
|
|
|
|
memcpy(&byteArrayBody(t, array, 0), source, length);
|
|
|
|
array = internByteArray(t, array);
|
|
|
|
|
|
|
|
set(t, class_, ClassSource, array);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
object bootstrapClass = hashMapFind
|
|
|
|
(t, root(t, Machine::BootstrapClassMap), spec, byteArrayHash,
|
|
|
|
byteArrayEqual);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
if (bootstrapClass) {
|
|
|
|
PROTECT(t, bootstrapClass);
|
|
|
|
|
|
|
|
updateBootstrapClass(t, bootstrapClass, class_);
|
|
|
|
class_ = bootstrapClass;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (class_) {
|
2010-09-22 19:58:46 +00:00
|
|
|
hashMapInsert(t, classLoaderMap(t, loader), spec, class_, byteArrayHash);
|
2010-12-27 22:55:23 +00:00
|
|
|
} else if (throw_) {
|
2011-03-18 03:42:15 +00:00
|
|
|
throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0));
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
2007-07-11 04:19:26 +00:00
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
return class_;
|
|
|
|
}
|
|
|
|
|
2009-08-10 13:56:16 +00:00
|
|
|
object
|
2010-09-14 16:49:41 +00:00
|
|
|
findLoadedClass(Thread* t, object loader, object spec)
|
|
|
|
{
|
2010-09-22 19:58:46 +00:00
|
|
|
PROTECT(t, loader);
|
2010-09-14 16:49:41 +00:00
|
|
|
PROTECT(t, spec);
|
2010-09-22 19:58:46 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
ACQUIRE(t, t->m->classLock);
|
|
|
|
|
2010-09-22 19:58:46 +00:00
|
|
|
return classLoaderMap(t, loader) ? hashMapFind
|
|
|
|
(t, classLoaderMap(t, loader), spec, byteArrayHash, byteArrayEqual) : 0;
|
2010-09-14 16:49:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
2011-03-18 03:42:15 +00:00
|
|
|
resolveClass(Thread* t, object loader, object spec, bool throw_,
|
|
|
|
Machine::Type throwType)
|
2009-08-10 13:56:16 +00:00
|
|
|
{
|
2010-09-22 19:58:46 +00:00
|
|
|
if (objectClass(t, loader) == type(t, Machine::SystemClassLoaderType)) {
|
2011-03-18 03:42:15 +00:00
|
|
|
return resolveSystemClass(t, loader, spec, throw_, throwType);
|
2009-08-10 13:56:16 +00:00
|
|
|
} else {
|
2010-11-27 21:44:49 +00:00
|
|
|
PROTECT(t, loader);
|
|
|
|
PROTECT(t, spec);
|
|
|
|
|
2010-12-01 03:27:36 +00:00
|
|
|
object c = findLoadedClass(t, loader, spec);
|
|
|
|
if (c) {
|
|
|
|
return c;
|
2010-09-17 01:43:27 +00:00
|
|
|
}
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2010-09-17 01:43:27 +00:00
|
|
|
if (byteArrayBody(t, spec, 0) == '[') {
|
2011-03-18 03:42:15 +00:00
|
|
|
c = resolveArrayClass(t, loader, spec, throw_, throwType);
|
2010-09-17 01:43:27 +00:00
|
|
|
} else {
|
|
|
|
if (root(t, Machine::LoadClassMethod) == 0) {
|
|
|
|
object m = resolveMethod
|
|
|
|
(t, root(t, Machine::BootLoader), "java/lang/ClassLoader",
|
|
|
|
"loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
|
|
|
|
|
|
|
if (m) {
|
|
|
|
setRoot(t, Machine::LoadClassMethod, m);
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2010-09-17 01:43:27 +00:00
|
|
|
object classLoaderClass = type(t, Machine::ClassLoaderType);
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2010-09-17 01:43:27 +00:00
|
|
|
if (classVmFlags(t, classLoaderClass) & BootstrapFlag) {
|
|
|
|
resolveSystemClass
|
|
|
|
(t, root(t, Machine::BootLoader),
|
|
|
|
vm::className(t, classLoaderClass));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
object method = findVirtualMethod
|
|
|
|
(t, root(t, Machine::LoadClassMethod), objectClass(t, loader));
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
PROTECT(t, method);
|
|
|
|
|
|
|
|
THREAD_RUNTIME_ARRAY(t, char, s, byteArrayLength(t, spec));
|
|
|
|
replace('/', '.', RUNTIME_ARRAY_BODY(s), reinterpret_cast<char*>
|
|
|
|
(&byteArrayBody(t, spec, 0)));
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
object specString = makeString(t, "%s", RUNTIME_ARRAY_BODY(s));
|
2011-03-18 03:42:15 +00:00
|
|
|
PROTECT(t, specString);
|
2010-09-22 19:58:46 +00:00
|
|
|
|
2011-03-15 23:52:02 +00:00
|
|
|
uintptr_t arguments[] = { reinterpret_cast<uintptr_t>(method),
|
|
|
|
reinterpret_cast<uintptr_t>(loader),
|
|
|
|
reinterpret_cast<uintptr_t>(specString) };
|
|
|
|
|
|
|
|
object jc = reinterpret_cast<object>
|
|
|
|
(runRaw(t, invokeLoadClass, arguments));
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
if (LIKELY(jc)) {
|
|
|
|
c = jclassVmClass(t, jc);
|
2011-03-15 23:52:02 +00:00
|
|
|
} else if (t->exception) {
|
|
|
|
if (throw_) {
|
2011-03-18 03:42:15 +00:00
|
|
|
object e = type(t, throwType) == objectClass(t, t->exception)
|
|
|
|
? t->exception
|
|
|
|
: makeThrowable(t, throwType, specString, 0, t->exception);
|
2011-03-15 23:52:02 +00:00
|
|
|
t->exception = 0;
|
|
|
|
vm::throw_(t, e);
|
|
|
|
} else {
|
|
|
|
t->exception = 0;
|
|
|
|
}
|
2010-12-01 03:27:36 +00:00
|
|
|
}
|
|
|
|
}
|
2010-09-22 19:58:46 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
if (LIKELY(c)) {
|
2010-12-01 03:27:36 +00:00
|
|
|
PROTECT(t, c);
|
2009-08-11 15:20:49 +00:00
|
|
|
|
2011-03-27 05:21:37 +00:00
|
|
|
saveLoadedClass(t, loader, c);
|
2011-03-15 23:52:02 +00:00
|
|
|
} else if (throw_) {
|
2011-03-18 03:42:15 +00:00
|
|
|
throwNew(t, throwType, "%s", &byteArrayBody(t, spec, 0));
|
2009-08-10 13:56:16 +00:00
|
|
|
}
|
2011-03-15 23:52:02 +00:00
|
|
|
|
|
|
|
return c;
|
2009-08-10 13:56:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
object
|
2009-06-11 00:15:00 +00:00
|
|
|
resolveMethod(Thread* t, object class_, const char* methodName,
|
2007-09-24 01:39:03 +00:00
|
|
|
const char* methodSpec)
|
|
|
|
{
|
2009-06-11 00:15:00 +00:00
|
|
|
PROTECT(t, class_);
|
2007-09-24 01:39:03 +00:00
|
|
|
|
2009-06-11 00:15:00 +00:00
|
|
|
object name = makeByteArray(t, methodName);
|
|
|
|
PROTECT(t, name);
|
2007-09-24 01:39:03 +00:00
|
|
|
|
2009-06-11 00:15:00 +00:00
|
|
|
object spec = makeByteArray(t, methodSpec);
|
2007-09-24 01:39:03 +00:00
|
|
|
|
2009-06-11 00:15:00 +00:00
|
|
|
object method = findMethodInClass(t, class_, name, spec);
|
2009-06-03 00:55:12 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
if (method == 0) {
|
|
|
|
throwNew(t, Machine::NoSuchMethodErrorType, "%s %s not found in %s",
|
|
|
|
methodName, methodSpec, &byteArrayBody
|
|
|
|
(t, className(t, class_), 0));
|
2009-06-11 00:15:00 +00:00
|
|
|
} else {
|
|
|
|
return method;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
resolveField(Thread* t, object class_, const char* fieldName,
|
|
|
|
const char* fieldSpec)
|
|
|
|
{
|
|
|
|
PROTECT(t, class_);
|
|
|
|
|
|
|
|
object name = makeByteArray(t, fieldName);
|
|
|
|
PROTECT(t, name);
|
|
|
|
|
|
|
|
object spec = makeByteArray(t, fieldSpec);
|
|
|
|
PROTECT(t, spec);
|
|
|
|
|
2009-08-03 22:16:41 +00:00
|
|
|
object field = findInInterfaces(t, class_, name, spec, findFieldInClass);
|
|
|
|
|
2010-10-24 17:49:59 +00:00
|
|
|
object c = class_;
|
|
|
|
PROTECT(t, c);
|
|
|
|
|
|
|
|
for (; c != 0 and field == 0; c = classSuper(t, c)) {
|
|
|
|
field = findFieldInClass(t, c, name, spec);
|
2007-09-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
if (field == 0) {
|
|
|
|
throwNew(t, Machine::NoSuchFieldErrorType, "%s %s not found in %s",
|
|
|
|
fieldName, fieldSpec, &byteArrayBody(t, className(t, class_), 0));
|
2009-06-11 00:15:00 +00:00
|
|
|
} else {
|
|
|
|
return field;
|
|
|
|
}
|
2007-09-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
2009-07-20 20:12:38 +00:00
|
|
|
bool
|
|
|
|
classNeedsInit(Thread* t, object c)
|
|
|
|
{
|
|
|
|
if (classVmFlags(t, c) & NeedInitFlag) {
|
|
|
|
if (classVmFlags(t, c) & InitFlag) {
|
|
|
|
// the class is currently being initialized. If this the thread
|
|
|
|
// which is initializing it, we should not try to initialize it
|
|
|
|
// recursively. Otherwise, we must wait for the responsible
|
|
|
|
// thread to finish.
|
|
|
|
for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) {
|
|
|
|
if (s->class_ == c) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
preInitClass(Thread* t, object c)
|
|
|
|
{
|
2011-04-10 20:46:53 +00:00
|
|
|
int flags = classVmFlags(t, c);
|
|
|
|
|
|
|
|
loadMemoryBarrier();
|
|
|
|
|
|
|
|
if (flags & NeedInitFlag) {
|
2009-07-20 20:12:38 +00:00
|
|
|
PROTECT(t, c);
|
|
|
|
ACQUIRE(t, t->m->classLock);
|
2010-09-22 19:58:46 +00:00
|
|
|
|
2009-07-20 20:12:38 +00:00
|
|
|
if (classVmFlags(t, c) & NeedInitFlag) {
|
|
|
|
if (classVmFlags(t, c) & InitFlag) {
|
2010-08-05 00:27:54 +00:00
|
|
|
// If the class is currently being initialized and this the thread
|
|
|
|
// which is initializing it, we should not try to initialize it
|
|
|
|
// recursively.
|
2011-04-01 01:43:49 +00:00
|
|
|
if (isInitializing(t, c)) {
|
2010-08-05 00:27:54 +00:00
|
|
|
return false;
|
2009-07-20 20:12:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// some other thread is on the job - wait for it to finish.
|
|
|
|
while (classVmFlags(t, c) & InitFlag) {
|
|
|
|
ENTER(t, Thread::IdleState);
|
|
|
|
t->m->classLock->wait(t->systemThread, 0);
|
|
|
|
}
|
|
|
|
} else if (classVmFlags(t, c) & InitErrorFlag) {
|
2010-12-27 22:55:23 +00:00
|
|
|
throwNew(t, Machine::NoClassDefFoundErrorType, "%s",
|
|
|
|
&byteArrayBody(t, className(t, c), 0));
|
2009-07-20 20:12:38 +00:00
|
|
|
} else {
|
|
|
|
classVmFlags(t, c) |= InitFlag;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
postInitClass(Thread* t, object c)
|
|
|
|
{
|
|
|
|
PROTECT(t, c);
|
|
|
|
ACQUIRE(t, t->m->classLock);
|
2010-09-22 19:58:46 +00:00
|
|
|
|
2009-07-20 20:12:38 +00:00
|
|
|
if (t->exception) {
|
2010-12-27 22:55:23 +00:00
|
|
|
classVmFlags(t, c) |= NeedInitFlag | InitErrorFlag;
|
|
|
|
classVmFlags(t, c) &= ~InitFlag;
|
|
|
|
|
2010-12-20 23:49:45 +00:00
|
|
|
object exception = t->exception;
|
|
|
|
t->exception = 0;
|
2010-09-10 21:05:29 +00:00
|
|
|
|
2011-02-12 04:13:11 +00:00
|
|
|
throwNew(t, Machine::ExceptionInInitializerErrorType,
|
|
|
|
static_cast<object>(0), 0, exception);
|
2009-07-20 20:12:38 +00:00
|
|
|
} else {
|
|
|
|
classVmFlags(t, c) &= ~(NeedInitFlag | InitFlag);
|
|
|
|
}
|
|
|
|
t->m->classLock->notifyAll(t->systemThread);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
initClass(Thread* t, object c)
|
|
|
|
{
|
|
|
|
PROTECT(t, c);
|
|
|
|
|
2011-04-01 01:43:49 +00:00
|
|
|
object super = classSuper(t, c);
|
|
|
|
if (super) {
|
|
|
|
initClass(t, super);
|
|
|
|
}
|
|
|
|
|
2009-07-20 20:12:38 +00:00
|
|
|
if (preInitClass(t, c)) {
|
2010-12-27 22:55:23 +00:00
|
|
|
OBJECT_RESOURCE(t, c, postInitClass(t, c));
|
|
|
|
|
2011-04-01 01:43:49 +00:00
|
|
|
object initializer = classInitializer(t, c);
|
|
|
|
|
|
|
|
if (initializer) {
|
|
|
|
Thread::ClassInitStack stack(t, c);
|
2009-07-20 20:12:38 +00:00
|
|
|
|
2011-04-01 01:43:49 +00:00
|
|
|
t->m->processor->invoke(t, initializer, 0);
|
|
|
|
}
|
2009-07-20 20:12:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-27 23:27:30 +00:00
|
|
|
object
|
|
|
|
resolveObjectArrayClass(Thread* t, object loader, object elementClass)
|
|
|
|
{
|
2011-11-18 15:38:19 +00:00
|
|
|
PROTECT(t, loader);
|
|
|
|
PROTECT(t, elementClass);
|
|
|
|
|
2010-11-27 23:27:30 +00:00
|
|
|
{ object arrayClass = classRuntimeDataArrayClass
|
|
|
|
(t, getClassRuntimeData(t, elementClass));
|
|
|
|
if (arrayClass) {
|
|
|
|
return arrayClass;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object elementSpec = className(t, elementClass);
|
|
|
|
PROTECT(t, elementSpec);
|
|
|
|
|
|
|
|
object spec;
|
|
|
|
if (byteArrayBody(t, elementSpec, 0) == '[') {
|
|
|
|
spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 1);
|
|
|
|
byteArrayBody(t, spec, 0) = '[';
|
|
|
|
memcpy(&byteArrayBody(t, spec, 1),
|
|
|
|
&byteArrayBody(t, elementSpec, 0),
|
|
|
|
byteArrayLength(t, elementSpec));
|
|
|
|
} else {
|
|
|
|
spec = makeByteArray(t, byteArrayLength(t, elementSpec) + 3);
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
object arrayClass = resolveClass(t, loader, spec);
|
|
|
|
|
|
|
|
set(t, getClassRuntimeData(t, elementClass), ClassRuntimeDataArrayClass,
|
|
|
|
arrayClass);
|
|
|
|
|
|
|
|
return arrayClass;
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
object
|
2010-09-14 16:49:41 +00:00
|
|
|
makeObjectArray(Thread* t, object elementClass, unsigned count)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
2009-08-10 13:56:16 +00:00
|
|
|
object arrayClass = resolveObjectArrayClass
|
2010-09-25 21:54:01 +00:00
|
|
|
(t, classLoader(t, elementClass), elementClass);
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-10 02:38:12 +00:00
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, arrayClass);
|
|
|
|
|
2009-03-04 03:05:48 +00:00
|
|
|
object array = makeArray(t, count);
|
2007-07-14 17:31:01 +00:00
|
|
|
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);
|
2009-08-27 00:26:44 +00:00
|
|
|
if (vm::strcmp(&byteArrayBody(t, getName(t, o), 0),
|
|
|
|
&byteArrayBody(t, name, 0)) == 0 and
|
|
|
|
vm::strcmp(&byteArrayBody(t, getSpec(t, o), 0),
|
|
|
|
&byteArrayBody(t, spec, 0)) == 0)
|
2007-09-07 00:21:52 +00:00
|
|
|
{
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
}
|
2008-01-19 00:54:36 +00:00
|
|
|
|
2008-01-19 01:49:30 +00:00
|
|
|
// fprintf(stderr, "%s %s not in\n",
|
|
|
|
// &byteArrayBody(t, name, 0),
|
|
|
|
// &byteArrayBody(t, spec, 0));
|
|
|
|
|
|
|
|
// for (unsigned i = 0; i < arrayLength(t, table); ++i) {
|
|
|
|
// object o = arrayBody(t, table, i);
|
|
|
|
// fprintf(stderr, "\t%s %s\n",
|
|
|
|
// &byteArrayBody(t, getName(t, o), 0),
|
|
|
|
// &byteArrayBody(t, getSpec(t, o), 0));
|
|
|
|
// }
|
2007-09-07 00:21:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
2010-11-04 17:02:09 +00:00
|
|
|
findInHierarchyOrNull(Thread* t, object class_, object name, object spec,
|
|
|
|
object (*find)(Thread*, object, object, object))
|
2007-09-07 00:21:52 +00:00
|
|
|
{
|
|
|
|
object originalClass = class_;
|
|
|
|
|
|
|
|
object o = 0;
|
2008-11-11 15:20:49 +00:00
|
|
|
if ((classFlags(t, class_) & ACC_INTERFACE)
|
|
|
|
and classVirtualTable(t, class_))
|
|
|
|
{
|
|
|
|
o = findInTable
|
|
|
|
(t, classVirtualTable(t, class_), name, spec, methodName, methodSpec);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (o == 0) {
|
2007-09-07 00:21:52 +00:00
|
|
|
for (; o == 0 and class_; class_ = classSuper(t, class_)) {
|
|
|
|
o = find(t, class_, name, spec);
|
|
|
|
}
|
2009-12-25 00:57:07 +00:00
|
|
|
|
|
|
|
if (o == 0 and find == findFieldInClass) {
|
|
|
|
o = findInInterfaces(t, originalClass, name, spec, find);
|
|
|
|
}
|
2007-09-07 00:21:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2007-11-20 22:24:02 +00:00
|
|
|
unsigned
|
|
|
|
parameterFootprint(Thread* t, const char* s, bool static_)
|
|
|
|
{
|
|
|
|
unsigned footprint = 0;
|
|
|
|
for (MethodSpecIterator it(t, s); it.hasNext();) {
|
|
|
|
switch (*it.next()) {
|
|
|
|
case 'J':
|
|
|
|
case 'D':
|
|
|
|
footprint += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
++ footprint;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (not static_) {
|
|
|
|
++ footprint;
|
|
|
|
}
|
|
|
|
return footprint;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
2011-03-26 01:11:38 +00:00
|
|
|
object f = makeFinalizer(t, 0, function, 0, 0, 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
|
|
|
}
|
|
|
|
|
2010-02-05 00:56:21 +00:00
|
|
|
object
|
2007-11-27 22:23:00 +00:00
|
|
|
objectMonitor(Thread* t, object o, bool createNew)
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
2008-01-18 01:27:44 +00:00
|
|
|
assert(t, t->state == Thread::ActiveState);
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
object m = hashMapFind
|
|
|
|
(t, root(t, Machine::MonitorMap), o, objectHash, objectEqual);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2010-02-05 00:56:21 +00:00
|
|
|
if (m) {
|
2007-07-10 23:34:53 +00:00
|
|
|
if (DebugMonitors) {
|
2010-02-05 00:56:21 +00:00
|
|
|
fprintf(stderr, "found monitor %p for object %x\n", m, objectHash(t, o));
|
2007-07-10 23:34:53 +00:00
|
|
|
}
|
2007-07-10 03:04:49 +00:00
|
|
|
|
2010-02-05 00:56:21 +00:00
|
|
|
return m;
|
2007-11-27 22:23:00 +00:00
|
|
|
} else if (createNew) {
|
2007-07-06 23:50:26 +00:00
|
|
|
PROTECT(t, o);
|
2010-02-05 00:56:21 +00:00
|
|
|
PROTECT(t, m);
|
|
|
|
|
|
|
|
{ ENTER(t, Thread::ExclusiveState);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
m = hashMapFind
|
|
|
|
(t, root(t, Machine::MonitorMap), o, objectHash, objectEqual);
|
|
|
|
|
2010-02-05 00:56:21 +00:00
|
|
|
if (m) {
|
|
|
|
if (DebugMonitors) {
|
|
|
|
fprintf(stderr, "found monitor %p for object %x\n",
|
|
|
|
m, objectHash(t, o));
|
|
|
|
}
|
|
|
|
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
object head = makeMonitorNode(t, 0, 0);
|
|
|
|
m = makeMonitor(t, 0, 0, 0, head, head, 0);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2007-11-29 15:03:45 +00:00
|
|
|
if (DebugMonitors) {
|
2010-02-05 00:56:21 +00:00
|
|
|
fprintf(stderr, "made monitor %p for object %x\n", m,
|
2010-02-04 15:18:39 +00:00
|
|
|
objectHash(t, o));
|
2007-11-29 15:03:45 +00:00
|
|
|
}
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
hashMapInsert(t, root(t, Machine::MonitorMap), o, m, objectHash);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2010-02-05 00:56:21 +00:00
|
|
|
addFinalizer(t, o, removeMonitor);
|
2007-07-10 23:34:53 +00:00
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
|
|
|
|
return m;
|
2007-11-27 22:23:00 +00:00
|
|
|
} else {
|
|
|
|
return 0;
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-29 00:02:32 +00:00
|
|
|
object
|
|
|
|
intern(Thread* t, object s)
|
|
|
|
{
|
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
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
object n = hashMapFindNode
|
|
|
|
(t, root(t, Machine::StringMap), s, stringHash, stringEqual);
|
|
|
|
|
2007-07-29 00:02:32 +00:00
|
|
|
if (n) {
|
|
|
|
return jreferenceTarget(t, tripleFirst(t, n));
|
|
|
|
} else {
|
2010-09-14 16:49:41 +00:00
|
|
|
hashMapInsert(t, root(t, Machine::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)
|
|
|
|
{
|
2008-05-05 13:04:53 +00:00
|
|
|
ENTER(t, Thread::ExclusiveState);
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
if (t->m->heap->limitExceeded()) {
|
|
|
|
type = Heap::MajorCollection;
|
2007-08-22 14:50:29 +00:00
|
|
|
}
|
2007-10-28 01:54:30 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
doCollect(t, type);
|
2007-12-16 22:41:07 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
if (t->m->heap->limitExceeded()) {
|
|
|
|
// try once more, giving the heap a chance to squeeze everything
|
|
|
|
// into the smallest possible space:
|
|
|
|
doCollect(t, Heap::MajorCollection);
|
2009-07-17 15:29:24 +00:00
|
|
|
}
|
2011-02-02 15:46:20 +00:00
|
|
|
|
|
|
|
#ifdef AVIAN_HEAPDUMP
|
|
|
|
if ((not t->m->dumpedHeapOnOOM) and t->m->heap->limitExceeded()) {
|
|
|
|
t->m->dumpedHeapOnOOM = true;
|
|
|
|
const char* path = findProperty(t, "avian.heap.dump");
|
|
|
|
if (path) {
|
|
|
|
FILE* out = vm::fopen(path, "wb");
|
|
|
|
if (out) {
|
|
|
|
dumpHeap(t, out);
|
|
|
|
fclose(out);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif//AVIAN_HEAPDUMP
|
2007-07-16 01:03:02 +00:00
|
|
|
}
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
void
|
|
|
|
walk(Thread* t, Heap::Walker* w, object o, unsigned start)
|
|
|
|
{
|
|
|
|
object class_ = static_cast<object>(t->m->heap->follow(objectClass(t, o)));
|
|
|
|
object objectMask = static_cast<object>
|
|
|
|
(t->m->heap->follow(classObjectMask(t, class_)));
|
|
|
|
|
2009-05-17 23:43:48 +00:00
|
|
|
bool more = true;
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
if (objectMask) {
|
|
|
|
unsigned fixedSize = classFixedSize(t, class_);
|
|
|
|
unsigned arrayElementSize = classArrayElementSize(t, class_);
|
|
|
|
unsigned arrayLength
|
|
|
|
= (arrayElementSize ?
|
|
|
|
cast<uintptr_t>(o, fixedSize - BytesPerWord) : 0);
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, uint32_t, mask, intArrayLength(t, objectMask));
|
2009-08-27 00:26:44 +00:00
|
|
|
memcpy(RUNTIME_ARRAY_BODY(mask), &intArrayBody(t, objectMask, 0),
|
2008-11-21 23:20:35 +00:00
|
|
|
intArrayLength(t, objectMask) * 4);
|
|
|
|
|
2009-08-27 00:26:44 +00:00
|
|
|
more = ::walk(t, w, RUNTIME_ARRAY_BODY(mask), fixedSize, arrayElementSize,
|
|
|
|
arrayLength, start);
|
2009-08-18 20:26:28 +00:00
|
|
|
} else if (classVmFlags(t, class_) & SingletonFlag) {
|
2008-11-21 23:20:35 +00:00
|
|
|
unsigned length = singletonLength(t, o);
|
|
|
|
if (length) {
|
2009-05-17 23:43:48 +00:00
|
|
|
more = ::walk(t, w, singletonMask(t, o),
|
|
|
|
(singletonCount(t, o) + 2) * BytesPerWord, 0, 0, start);
|
2008-11-21 23:20:35 +00:00
|
|
|
} else if (start == 0) {
|
2009-05-17 23:43:48 +00:00
|
|
|
more = w->visit(0);
|
2008-11-21 23:20:35 +00:00
|
|
|
}
|
|
|
|
} else if (start == 0) {
|
2009-05-17 23:43:48 +00:00
|
|
|
more = w->visit(0);
|
2008-11-21 23:20:35 +00:00
|
|
|
}
|
2009-05-03 20:57:11 +00:00
|
|
|
|
2009-08-18 20:26:28 +00:00
|
|
|
if (more and classVmFlags(t, class_) & ContinuationFlag) {
|
2009-05-03 20:57:11 +00:00
|
|
|
t->m->processor->walkContinuationBody(t, w, o, start);
|
|
|
|
}
|
2008-11-21 23:20:35 +00:00
|
|
|
}
|
|
|
|
|
2008-11-11 15:20:49 +00:00
|
|
|
int
|
|
|
|
walkNext(Thread* t, object o, int previous)
|
|
|
|
{
|
|
|
|
class Walker: public Heap::Walker {
|
|
|
|
public:
|
|
|
|
Walker(): value(-1) { }
|
|
|
|
|
|
|
|
bool visit(unsigned offset) {
|
|
|
|
value = offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int value;
|
|
|
|
} walker;
|
|
|
|
|
|
|
|
walk(t, &walker, o, previous + 1);
|
|
|
|
return walker.value;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
visitRoots(Machine* m, Heap::Visitor* v)
|
|
|
|
{
|
|
|
|
v->visit(&(m->types));
|
2010-09-14 16:49:41 +00:00
|
|
|
v->visit(&(m->roots));
|
2008-11-11 15:20:49 +00:00
|
|
|
|
|
|
|
for (Thread* t = m->rootThread; t; t = t->peer) {
|
|
|
|
::visitRoots(t, v);
|
|
|
|
}
|
2009-05-03 20:57:11 +00:00
|
|
|
|
|
|
|
for (Reference* r = m->jniReferences; r; r = r->next) {
|
|
|
|
v->visit(&(r->target));
|
|
|
|
}
|
2008-11-11 15:20:49 +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) {
|
avoid inifinite recursion if java.lang.Object is missing; refactoring
When trying to create an array class, we try to resolve
java.lang.Object so we can use its vtable in the array class.
However, if Object is missing, we'll try to create and throw a
ClassNotFoundException, which requires creating an array to store the
stack trace, which requires creating an array class, which requires
resolving Object, etc.. This commit short-circuits this process by
telling resolveClass not to create and throw an exception if it can't
find Object.
While doing the above work, I noticed that the implementations of
Classpath::makeThrowable in classpath-avian.cpp and
classpath-openjdk.cpp were identical, so I made makeThrowable a
top-level function.
Finally, I discovered that Thread.setDaemon can only be called before
the target thread has been started, which allowed me to simplify the
code to track daemon threads in the VM.
2010-12-10 02:38:12 +00:00
|
|
|
exception = makeThrowable(t, Machine::NullPointerExceptionType);
|
2007-10-12 20:54:37 +00:00
|
|
|
}
|
2007-10-13 00:22:52 +00:00
|
|
|
|
2007-11-04 21:15:28 +00:00
|
|
|
for (object e = exception; e; e = throwableCause(t, e)) {
|
2007-07-24 03:16:59 +00:00
|
|
|
if (e != exception) {
|
2011-03-15 23:27:17 +00:00
|
|
|
fprintf(errorLog(t), "caused by: ");
|
2007-07-24 03:16:59 +00:00
|
|
|
}
|
|
|
|
|
2011-03-15 23:27:17 +00:00
|
|
|
fprintf(errorLog(t), "%s", &byteArrayBody
|
2007-07-24 03:16:59 +00:00
|
|
|
(t, className(t, objectClass(t, e)), 0));
|
|
|
|
|
2007-11-04 21:15:28 +00:00
|
|
|
if (throwableMessage(t, e)) {
|
|
|
|
object m = throwableMessage(t, e);
|
2010-12-27 22:55:23 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, message, stringLength(t, m) + 1);
|
2009-08-27 00:26:44 +00:00
|
|
|
stringChars(t, m, RUNTIME_ARRAY_BODY(message));
|
2011-03-15 23:27:17 +00:00
|
|
|
fprintf(errorLog(t), ": %s\n", RUNTIME_ARRAY_BODY(message));
|
2007-07-24 03:16:59 +00:00
|
|
|
} else {
|
2011-03-15 23:27:17 +00:00
|
|
|
fprintf(errorLog(t), "\n");
|
2007-07-24 03:16:59 +00:00
|
|
|
}
|
|
|
|
|
2007-11-04 21:15:28 +00:00
|
|
|
object trace = throwableTrace(t, e);
|
2011-03-04 22:58:10 +00:00
|
|
|
if (trace) {
|
|
|
|
for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) {
|
|
|
|
object e = objectArrayBody(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);
|
|
|
|
int line = t->m->processor->lineNumber
|
|
|
|
(t, traceElementMethod(t, e), traceElementIp(t, e));
|
|
|
|
|
2011-03-15 23:27:17 +00:00
|
|
|
fprintf(errorLog(t), " at %s.%s ", class_, method);
|
2011-03-04 22:58:10 +00:00
|
|
|
|
|
|
|
switch (line) {
|
|
|
|
case NativeLine:
|
2011-03-15 23:27:17 +00:00
|
|
|
fprintf(errorLog(t), "(native)\n");
|
2011-03-04 22:58:10 +00:00
|
|
|
break;
|
|
|
|
case UnknownLine:
|
2011-03-15 23:27:17 +00:00
|
|
|
fprintf(errorLog(t), "(unknown line)\n");
|
2011-03-04 22:58:10 +00:00
|
|
|
break;
|
|
|
|
default:
|
2011-03-15 23:27:17 +00:00
|
|
|
fprintf(errorLog(t), "(line %d)\n", line);
|
2011-03-04 22:58:10 +00:00
|
|
|
}
|
2007-07-24 03:16:59 +00:00
|
|
|
}
|
|
|
|
}
|
2010-09-10 21:05:29 +00:00
|
|
|
|
|
|
|
if (e == throwableCause(t, e)) {
|
|
|
|
break;
|
|
|
|
}
|
2007-07-24 03:16:59 +00:00
|
|
|
}
|
2010-12-01 03:27:36 +00:00
|
|
|
|
2011-03-15 23:27:17 +00:00
|
|
|
fflush(errorLog(t));
|
2007-07-24 03:16:59 +00:00
|
|
|
}
|
|
|
|
|
2007-09-24 01:39:03 +00:00
|
|
|
object
|
2007-11-25 23:00:55 +00:00
|
|
|
makeTrace(Thread* t, Processor::StackWalker* walker)
|
2007-09-24 01:39:03 +00:00
|
|
|
{
|
2007-11-25 23:00:55 +00:00
|
|
|
class Visitor: public Processor::StackVisitor {
|
|
|
|
public:
|
|
|
|
Visitor(Thread* t): t(t), trace(0), index(0), protector(t, &trace) { }
|
2007-09-24 13:46:48 +00:00
|
|
|
|
2007-11-25 23:00:55 +00:00
|
|
|
virtual bool visit(Processor::StackWalker* walker) {
|
|
|
|
if (trace == 0) {
|
2010-09-14 16:49:41 +00:00
|
|
|
trace = makeObjectArray(t, walker->count());
|
2010-12-20 23:49:45 +00:00
|
|
|
vm_assert(t, trace);
|
2007-11-25 23:00:55 +00:00
|
|
|
}
|
2007-09-24 01:39:03 +00:00
|
|
|
|
2007-11-25 23:00:55 +00:00
|
|
|
object e = makeTraceElement(t, walker->method(), walker->ip());
|
2010-09-14 16:49:41 +00:00
|
|
|
vm_assert(t, index < objectArrayLength(t, trace));
|
2007-11-25 23:00:55 +00:00
|
|
|
set(t, trace, ArrayBody + (index * BytesPerWord), e);
|
|
|
|
++ index;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Thread* t;
|
|
|
|
object trace;
|
|
|
|
unsigned index;
|
|
|
|
Thread::SingleProtector protector;
|
|
|
|
} v(t);
|
|
|
|
|
|
|
|
walker->walk(&v);
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
return v.trace ? v.trace : makeObjectArray(t, 0);
|
2007-11-25 23:00:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
2008-04-09 19:08:13 +00:00
|
|
|
makeTrace(Thread* t, Thread* target)
|
2007-11-25 23:00:55 +00:00
|
|
|
{
|
|
|
|
class Visitor: public Processor::StackVisitor {
|
|
|
|
public:
|
|
|
|
Visitor(Thread* t): t(t), trace(0) { }
|
|
|
|
|
|
|
|
virtual bool visit(Processor::StackWalker* walker) {
|
2009-08-27 00:26:44 +00:00
|
|
|
trace = vm::makeTrace(t, walker);
|
2007-11-25 23:00:55 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Thread* t;
|
|
|
|
object trace;
|
|
|
|
} v(t);
|
|
|
|
|
2008-04-09 19:08:13 +00:00
|
|
|
t->m->processor->walkStack(target, &v);
|
2007-09-24 01:39:03 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
return v.trace ? v.trace : makeObjectArray(t, 0);
|
2007-09-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
2009-08-24 23:51:31 +00:00
|
|
|
void
|
|
|
|
runFinalizeThread(Thread* t)
|
|
|
|
{
|
2011-03-26 01:11:38 +00:00
|
|
|
object finalizeList = 0;
|
|
|
|
PROTECT(t, finalizeList);
|
|
|
|
|
|
|
|
object cleanList = 0;
|
|
|
|
PROTECT(t, cleanList);
|
2009-08-24 23:51:31 +00:00
|
|
|
|
|
|
|
while (true) {
|
|
|
|
{ ACQUIRE(t, t->m->stateLock);
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
while (t->m->finalizeThread
|
2011-03-26 01:11:38 +00:00
|
|
|
and root(t, Machine::ObjectsToFinalize) == 0
|
|
|
|
and root(t, Machine::ObjectsToClean) == 0)
|
2010-09-14 16:49:41 +00:00
|
|
|
{
|
2009-08-24 23:51:31 +00:00
|
|
|
ENTER(t, Thread::IdleState);
|
|
|
|
t->m->stateLock->wait(t->systemThread, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (t->m->finalizeThread == 0) {
|
|
|
|
return;
|
|
|
|
} else {
|
2011-03-26 01:11:38 +00:00
|
|
|
finalizeList = root(t, Machine::ObjectsToFinalize);
|
2010-09-14 16:49:41 +00:00
|
|
|
setRoot(t, Machine::ObjectsToFinalize, 0);
|
2011-03-26 01:11:38 +00:00
|
|
|
|
|
|
|
cleanList = root(t, Machine::ObjectsToClean);
|
|
|
|
setRoot(t, Machine::ObjectsToClean, 0);
|
2009-08-24 23:51:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-26 01:11:38 +00:00
|
|
|
for (; finalizeList; finalizeList = finalizerQueueNext(t, finalizeList)) {
|
|
|
|
finalizeObject(t, finalizerQueueTarget(t, finalizeList), "finalize");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; cleanList; cleanList = cleanerQueueNext(t, cleanList)) {
|
|
|
|
finalizeObject(t, cleanList, "clean");
|
2009-08-24 23:51:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-10 21:05:29 +00:00
|
|
|
object
|
|
|
|
parseUtf8(Thread* t, const char* data, unsigned length)
|
|
|
|
{
|
|
|
|
class Client: public Stream::Client {
|
|
|
|
public:
|
|
|
|
Client(Thread* t): t(t) { }
|
|
|
|
|
2011-04-07 20:26:54 +00:00
|
|
|
virtual void handleError() {
|
|
|
|
// vm::abort(t);
|
2010-09-10 21:05:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Thread* t;
|
|
|
|
} client(t);
|
|
|
|
|
|
|
|
Stream s(&client, reinterpret_cast<const uint8_t*>(data), length);
|
|
|
|
|
|
|
|
return ::parseUtf8(t, s, length);
|
|
|
|
}
|
|
|
|
|
2010-09-25 21:54:01 +00:00
|
|
|
object
|
|
|
|
getCaller(Thread* t, unsigned target)
|
|
|
|
{
|
|
|
|
class Visitor: public Processor::StackVisitor {
|
|
|
|
public:
|
|
|
|
Visitor(Thread* t, unsigned target):
|
|
|
|
t(t), method(0), count(0), target(target)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual bool visit(Processor::StackWalker* walker) {
|
|
|
|
if (count == target) {
|
|
|
|
method = walker->method();
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
++ count;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Thread* t;
|
|
|
|
object method;
|
|
|
|
unsigned count;
|
|
|
|
unsigned target;
|
|
|
|
} v(t, target);
|
|
|
|
|
|
|
|
t->m->processor->walkStack(t, &v);
|
|
|
|
|
|
|
|
return v.method;
|
|
|
|
}
|
|
|
|
|
2010-09-10 21:05:29 +00:00
|
|
|
object
|
|
|
|
defineClass(Thread* t, object loader, const uint8_t* buffer, unsigned length)
|
|
|
|
{
|
|
|
|
PROTECT(t, loader);
|
|
|
|
|
|
|
|
object c = parseClass(t, loader, buffer, length);
|
2011-04-09 00:46:43 +00:00
|
|
|
|
|
|
|
// char name[byteArrayLength(t, className(t, c))];
|
|
|
|
// memcpy(name, &byteArrayBody(t, className(t, c), 0),
|
|
|
|
// byteArrayLength(t, className(t, c)));
|
|
|
|
// replace('/', '-', name);
|
2010-09-10 21:05:29 +00:00
|
|
|
|
2011-04-09 00:46:43 +00:00
|
|
|
// const unsigned BufferSize = 1024;
|
|
|
|
// char path[BufferSize];
|
|
|
|
// snprintf(path, BufferSize, "/tmp/avian-define-class/%s.class", name);
|
2010-09-10 21:05:29 +00:00
|
|
|
|
2011-04-09 00:46:43 +00:00
|
|
|
// FILE* file = fopen(path, "wb");
|
|
|
|
// if (file) {
|
|
|
|
// fwrite(buffer, length, 1, file);
|
|
|
|
// fclose(file);
|
|
|
|
// }
|
|
|
|
|
|
|
|
PROTECT(t, c);
|
|
|
|
|
|
|
|
saveLoadedClass(t, loader, c);
|
2010-09-10 21:05:29 +00:00
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2011-03-26 17:15:52 +00:00
|
|
|
void
|
|
|
|
populateMultiArray(Thread* t, object array, int32_t* counts,
|
|
|
|
unsigned index, unsigned dimensions)
|
|
|
|
{
|
|
|
|
if (index + 1 == dimensions or counts[index] == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PROTECT(t, array);
|
|
|
|
|
|
|
|
object spec = className(t, objectClass(t, array));
|
|
|
|
PROTECT(t, spec);
|
|
|
|
|
|
|
|
object elementSpec = makeByteArray(t, byteArrayLength(t, spec) - 1);
|
|
|
|
memcpy(&byteArrayBody(t, elementSpec, 0),
|
|
|
|
&byteArrayBody(t, spec, 1),
|
|
|
|
byteArrayLength(t, spec) - 1);
|
|
|
|
|
|
|
|
object class_ = resolveClass
|
|
|
|
(t, classLoader(t, objectClass(t, array)), elementSpec);
|
|
|
|
PROTECT(t, class_);
|
|
|
|
|
|
|
|
for (int32_t i = 0; i < counts[index]; ++i) {
|
|
|
|
object a = makeArray(t, counts[index + 1]);
|
|
|
|
setObjectClass(t, a, class_);
|
|
|
|
set(t, array, ArrayBody + (i * BytesPerWord), a);
|
|
|
|
|
|
|
|
populateMultiArray(t, a, counts, index + 1, dimensions);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-10 01:43:43 +00:00
|
|
|
void
|
|
|
|
noop()
|
|
|
|
{ }
|
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
#include "type-constructors.cpp"
|
|
|
|
|
|
|
|
} // namespace vm
|
2008-01-16 17:30:12 +00:00
|
|
|
|
|
|
|
// for debugging
|
2008-01-16 17:48:14 +00:00
|
|
|
void
|
2008-01-16 17:30:12 +00:00
|
|
|
vmPrintTrace(Thread* t)
|
|
|
|
{
|
|
|
|
class Visitor: public Processor::StackVisitor {
|
|
|
|
public:
|
|
|
|
Visitor(Thread* t): t(t) { }
|
|
|
|
|
|
|
|
virtual bool visit(Processor::StackWalker* walker) {
|
|
|
|
const int8_t* class_ = &byteArrayBody
|
|
|
|
(t, className(t, methodClass(t, walker->method())), 0);
|
|
|
|
const int8_t* method = &byteArrayBody
|
|
|
|
(t, methodName(t, walker->method()), 0);
|
|
|
|
int line = t->m->processor->lineNumber
|
|
|
|
(t, walker->method(), walker->ip());
|
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
fprintf(stderr, " at %s.%s ", class_, method);
|
2008-01-16 17:30:12 +00:00
|
|
|
|
|
|
|
switch (line) {
|
|
|
|
case NativeLine:
|
|
|
|
fprintf(stderr, "(native)\n");
|
|
|
|
break;
|
|
|
|
case UnknownLine:
|
|
|
|
fprintf(stderr, "(unknown line)\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "(line %d)\n", line);
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Thread* t;
|
|
|
|
} v(t);
|
|
|
|
|
2010-09-17 01:43:27 +00:00
|
|
|
fprintf(stderr, "debug trace for thread %p\n", t);
|
|
|
|
|
2008-01-16 17:30:12 +00:00
|
|
|
t->m->processor->walkStack(t, &v);
|
2010-12-01 03:27:36 +00:00
|
|
|
|
|
|
|
fflush(stderr);
|
2008-01-16 17:30:12 +00:00
|
|
|
}
|
2009-06-11 15:44:37 +00:00
|
|
|
|
|
|
|
// also for debugging
|
|
|
|
void*
|
|
|
|
vmAddressFromLine(Thread* t, object m, unsigned line)
|
|
|
|
{
|
2010-09-17 01:43:27 +00:00
|
|
|
object code = methodCode(t, m);
|
|
|
|
printf("code: %p\n", code);
|
|
|
|
object lnt = codeLineNumberTable(t, code);
|
|
|
|
printf("lnt: %p\n", lnt);
|
2009-06-11 15:44:37 +00:00
|
|
|
|
2010-09-17 01:43:27 +00:00
|
|
|
if (lnt) {
|
|
|
|
unsigned last = 0;
|
|
|
|
unsigned bottom = 0;
|
|
|
|
unsigned top = lineNumberTableLength(t, lnt);
|
|
|
|
for(unsigned i = bottom; i < top; i++)
|
|
|
|
{
|
2011-08-30 01:00:17 +00:00
|
|
|
uint64_t ln = lineNumberTableBody(t, lnt, i);
|
2010-09-17 01:43:27 +00:00
|
|
|
if(lineNumberLine(ln) == line)
|
|
|
|
return reinterpret_cast<void*>(lineNumberIp(ln));
|
|
|
|
else if(lineNumberLine(ln) > line)
|
|
|
|
return reinterpret_cast<void*>(last);
|
|
|
|
last = lineNumberIp(ln);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2009-06-11 15:44:37 +00:00
|
|
|
}
|