2015-03-13 18:52:59 +00:00
|
|
|
/* Copyright (c) 2008-2015, 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. */
|
|
|
|
|
2013-02-27 20:25:50 +00:00
|
|
|
#include "avian/jnienv.h"
|
|
|
|
#include "avian/machine.h"
|
|
|
|
#include "avian/util.h"
|
2013-02-21 04:26:34 +00:00
|
|
|
#include <avian/util/stream.h>
|
2013-02-27 20:25:50 +00:00
|
|
|
#include "avian/constants.h"
|
|
|
|
#include "avian/processor.h"
|
|
|
|
#include "avian/arch.h"
|
|
|
|
#include "avian/lzma.h"
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2013-02-20 05:56:05 +00:00
|
|
|
#include <avian/util/runtime-array.h>
|
2013-02-20 14:51:57 +00:00
|
|
|
#include <avian/util/math.h>
|
2013-02-11 00:51:59 +00:00
|
|
|
|
2013-01-30 08:42:05 +00:00
|
|
|
#if defined(PLATFORM_WINDOWS)
|
2014-07-11 15:50:18 +00:00
|
|
|
#define WIN32_LEAN_AND_MEAN
|
|
|
|
#include <windows.h>
|
2013-01-30 08:42:05 +00:00
|
|
|
#endif
|
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
using namespace vm;
|
2013-02-20 14:51:57 +00:00
|
|
|
using namespace avian::util;
|
2007-07-06 23:50:26 +00:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2012-05-22 19:53:32 +00:00
|
|
|
const bool DebugClassReader = false;
|
|
|
|
|
2009-08-14 14:52:31 +00:00
|
|
|
const unsigned NoByte = 0xFFFF;
|
|
|
|
|
2009-11-28 22:01:54 +00:00
|
|
|
#ifdef USE_ATOMIC_OPERATIONS
|
2014-07-11 15:50:18 +00:00
|
|
|
void atomicIncrement(uint32_t* p, int v)
|
2009-11-28 22:01:54 +00:00
|
|
|
{
|
2014-07-11 15:50:18 +00:00
|
|
|
for (uint32_t old = *p; not atomicCompareAndSwap32(p, old, old + v);
|
|
|
|
old = *p) {
|
|
|
|
}
|
2009-11-28 22:01:54 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void join(Thread* t, Thread* o)
|
2007-07-07 18:09:16 +00:00
|
|
|
{
|
|
|
|
if (t != o) {
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, o->state != Thread::JoinedState);
|
2014-08-20 15:49:00 +00:00
|
|
|
assertT(t, (o->getFlags() & Thread::SystemFlag) == 0);
|
|
|
|
if (o->getFlags() & Thread::JoinFlag) {
|
2010-11-09 22:46:16 +00:00
|
|
|
o->systemThread->join();
|
|
|
|
}
|
2007-07-18 01:33:00 +00:00
|
|
|
o->state = Thread::JoinedState;
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-02 15:06:22 +00:00
|
|
|
#ifndef NDEBUG
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
bool find(Thread* t, Thread* o)
|
2012-06-02 15:06:22 +00:00
|
|
|
{
|
2014-07-11 15:50:18 +00:00
|
|
|
return (t == o) or (t->peer and find(t->peer, o))
|
|
|
|
or (t->child and find(t->child, o));
|
2012-06-02 15:06:22 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
unsigned count(Thread* t, Thread* o)
|
2012-06-02 15:06:22 +00:00
|
|
|
{
|
|
|
|
unsigned c = 0;
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (t != o)
|
|
|
|
++c;
|
|
|
|
if (t->peer)
|
|
|
|
c += count(t->peer, o);
|
|
|
|
if (t->child)
|
|
|
|
c += count(t->child, o);
|
2012-06-02 15:06:22 +00:00
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
Thread** fill(Thread* t, Thread* o, Thread** array)
|
2012-06-02 15:06:22 +00:00
|
|
|
{
|
2014-07-11 15:50:18 +00:00
|
|
|
if (t != o)
|
|
|
|
*(array++) = t;
|
|
|
|
if (t->peer)
|
|
|
|
array = fill(t->peer, o, array);
|
|
|
|
if (t->child)
|
|
|
|
array = fill(t->child, o, array);
|
2012-06-02 15:06:22 +00:00
|
|
|
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
#endif // not NDEBUG
|
2012-06-02 15:06:22 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void dispose(Thread* t, Thread* o, bool remove)
|
2007-07-07 18:09:16 +00:00
|
|
|
{
|
|
|
|
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
|
|
|
}
|
2014-07-11 15:50:18 +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();
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void 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
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void disposeNoRemove(Thread* m, Thread* o)
|
2007-07-07 18:09:16 +00:00
|
|
|
{
|
|
|
|
dispose(m, o, false);
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void interruptDaemon(Thread* m, Thread* o)
|
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
|
|
|
{
|
2014-08-20 15:49:00 +00:00
|
|
|
if (o->getFlags() & Thread::DaemonFlag) {
|
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(m, o);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void turnOffTheLights(Thread* t)
|
2009-08-19 20:27:03 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
{
|
|
|
|
GcFinalizer* p = 0;
|
2010-09-14 16:49:41 +00:00
|
|
|
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;) {
|
2014-05-29 04:17:25 +00:00
|
|
|
GcFinalizer* f = p;
|
|
|
|
p = cast<GcFinalizer>(t, p->next());
|
2010-09-14 16:49:41 +00:00
|
|
|
|
|
|
|
void (*function)(Thread*, object);
|
2014-05-29 04:17:25 +00:00
|
|
|
memcpy(&function, &f->finalize(), BytesPerWord);
|
2010-09-14 16:49:41 +00:00
|
|
|
if (function) {
|
2014-05-29 04:17:25 +00:00
|
|
|
function(t, f->target());
|
2010-09-14 16:49:41 +00:00
|
|
|
}
|
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;) {
|
2014-05-29 04:17:25 +00:00
|
|
|
GcFinalizer* f = p;
|
|
|
|
p = cast<GcFinalizer>(t, p->next());
|
2009-08-19 20:27:03 +00:00
|
|
|
|
2010-09-14 16:49:41 +00:00
|
|
|
void (*function)(Thread*, object);
|
2014-05-29 04:17:25 +00:00
|
|
|
memcpy(&function, &f->finalize(), BytesPerWord);
|
2010-09-14 16:49:41 +00:00
|
|
|
if (function) {
|
2014-05-29 04:17:25 +00:00
|
|
|
function(t, f->target());
|
2010-09-14 16:49:41 +00:00
|
|
|
}
|
2009-12-06 02:40:46 +00:00
|
|
|
}
|
2009-08-19 20:27:03 +00:00
|
|
|
}
|
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
if (GcArray* files = roots(t)->virtualFiles()) {
|
2014-06-29 05:48:17 +00:00
|
|
|
PROTECT(t, files);
|
2014-07-11 15:47:57 +00:00
|
|
|
for (unsigned i = 0; i < files->length(); ++i) {
|
2014-06-29 05:48:17 +00:00
|
|
|
object region = files->body()[i];
|
2010-11-05 19:18:28 +00:00
|
|
|
if (region) {
|
2014-07-11 15:47:57 +00:00
|
|
|
static_cast<System::Region*>(cast<GcRegion>(t, region)->region())
|
|
|
|
->dispose();
|
2010-11-05 19:18:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
for (GcFinder* p = roots(t)->virtualFileFinders(); p; p = p->next()) {
|
2014-06-29 05:48:17 +00:00
|
|
|
static_cast<Finder*>(p->finder())->dispose();
|
2010-11-05 19:18:28 +00:00
|
|
|
}
|
|
|
|
|
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;
|
2012-02-03 19:00:02 +00:00
|
|
|
|
|
|
|
expect(s, m->threadCount == 0);
|
|
|
|
|
2009-08-19 20:27:03 +00:00
|
|
|
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
|
|
|
h->disposeFixies();
|
2012-06-02 15:06:22 +00:00
|
|
|
m->dispose();
|
2009-08-19 20:27:03 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void 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);
|
|
|
|
}
|
|
|
|
|
2014-08-20 15:49:00 +00:00
|
|
|
if ((o->getFlags() & Thread::SystemFlag) == 0) {
|
2012-02-04 00:20:20 +00:00
|
|
|
switch (o->state) {
|
|
|
|
case Thread::ZombieState:
|
|
|
|
join(t, o);
|
2014-07-11 15:50:18 +00:00
|
|
|
// fall through
|
|
|
|
|
2012-02-04 00:20:20 +00:00
|
|
|
case Thread::JoinedState:
|
|
|
|
dispose(t, o, true);
|
2014-07-11 15:50:18 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2012-02-04 00:20:20 +00:00
|
|
|
}
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
unsigned footprint(Thread* t)
|
2007-08-18 21:24:29 +00:00
|
|
|
{
|
2012-09-12 23:23:19 +00:00
|
|
|
expect(t, t->criticalLevel == 0);
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void visitRoots(Thread* t, Heap::Visitor* v)
|
2007-07-07 23:47:35 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
bool walk(Thread*,
|
|
|
|
Heap::Walker* w,
|
|
|
|
uint32_t* mask,
|
|
|
|
unsigned fixedSize,
|
|
|
|
unsigned arrayElementSize,
|
|
|
|
unsigned arrayLength,
|
|
|
|
unsigned start)
|
2007-11-02 14:15:06 +00:00
|
|
|
{
|
2013-02-11 01:06:15 +00:00
|
|
|
unsigned fixedSizeInWords = ceilingDivide(fixedSize, BytesPerWord);
|
2007-11-02 14:15:06 +00:00
|
|
|
unsigned arrayElementSizeInWords
|
2014-07-11 15:50:18 +00:00
|
|
|
= ceilingDivide(arrayElementSize, BytesPerWord);
|
2007-11-02 14:15:06 +00:00
|
|
|
|
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))) {
|
2014-07-11 15:50:18 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
object findInInterfaces(
|
|
|
|
Thread* t,
|
|
|
|
GcClass* class_,
|
|
|
|
GcByteArray* name,
|
|
|
|
GcByteArray* spec,
|
|
|
|
object (*find)(Thread*, GcClass*, GcByteArray*, GcByteArray*))
|
2009-08-03 22:16:41 +00:00
|
|
|
{
|
|
|
|
object result = 0;
|
2014-06-29 05:48:17 +00:00
|
|
|
if (GcArray* itable = cast<GcArray>(t, class_->interfaceTable())) {
|
|
|
|
PROTECT(t, itable);
|
2014-07-11 15:47:57 +00:00
|
|
|
for (unsigned i = 0; i < itable->length() and result == 0; i += 2) {
|
|
|
|
result = find(t, cast<GcClass>(t, itable->body()[i]), name, spec);
|
2009-08-03 22:16:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void finalizerTargetUnreachable(Thread* t, Heap::Visitor* v, GcFinalizer** p)
|
2007-07-29 23:32:23 +00:00
|
|
|
{
|
2014-06-29 05:48:17 +00:00
|
|
|
v->visit(&(*p)->target());
|
2007-07-29 23:32:23 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcFinalizer* finalizer = *p;
|
|
|
|
*p = cast<GcFinalizer>(t, finalizer->next());
|
2011-03-26 01:11:38 +00:00
|
|
|
|
|
|
|
void (*function)(Thread*, object);
|
2014-06-29 05:48:17 +00:00
|
|
|
memcpy(&function, &finalizer->finalize(), BytesPerWord);
|
2011-03-26 01:11:38 +00:00
|
|
|
|
|
|
|
if (function) {
|
2014-06-29 05:48:17 +00:00
|
|
|
// TODO: use set() here?
|
2014-07-02 21:11:27 +00:00
|
|
|
finalizer->next() = t->m->finalizeQueue;
|
2014-06-29 05:48:17 +00:00
|
|
|
t->m->finalizeQueue = finalizer;
|
2011-03-26 01:11:38 +00:00
|
|
|
} else {
|
2014-06-26 01:42:16 +00:00
|
|
|
finalizer->setQueueTarget(t, finalizer->target());
|
|
|
|
finalizer->setQueueNext(t, roots(t)->objectsToFinalize());
|
|
|
|
roots(t)->setObjectsToFinalize(t, finalizer);
|
2011-03-26 01:11:38 +00:00
|
|
|
}
|
2007-07-29 23:32:23 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void referenceTargetUnreachable(Thread* t, Heap::Visitor* v, GcJreference** p)
|
2007-07-20 01:07:30 +00:00
|
|
|
{
|
2007-07-29 23:32:23 +00:00
|
|
|
if (DebugReferences) {
|
2014-07-11 15:47:57 +00:00
|
|
|
fprintf(
|
|
|
|
stderr, "target %p unreachable for reference %p\n", (*p)->target(), *p);
|
2007-07-29 23:32:23 +00:00
|
|
|
}
|
2007-07-21 17:50:26 +00:00
|
|
|
|
2007-10-28 19:14:53 +00:00
|
|
|
v->visit(p);
|
2014-06-29 05:48:17 +00:00
|
|
|
(*p)->target() = 0;
|
2007-07-20 01:07:30 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (objectClass(t, *p) == type(t, GcCleaner::Type)) {
|
2014-06-26 01:42:16 +00:00
|
|
|
// In openjdk, sun/misc/Cleaner extends PhantomReference
|
|
|
|
GcCleaner* cleaner = (*p)->as<GcCleaner>(t);
|
2011-03-26 01:11:38 +00:00
|
|
|
|
2014-07-17 23:53:36 +00:00
|
|
|
*p = cast<GcJreference>(t, (*p)->vmNext());
|
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
cleaner->setQueueNext(t, roots(t)->objectsToClean());
|
|
|
|
roots(t)->setObjectsToClean(t, cleaner);
|
2011-03-19 21:10:52 +00:00
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
if ((*p)->queue()
|
2014-07-11 15:47:57 +00:00
|
|
|
and t->m->heap->status((*p)->queue()) != Heap::Unreachable) {
|
2011-03-19 21:10:52 +00:00
|
|
|
// queue is reachable - add the reference
|
2007-07-20 01:07:30 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
v->visit(&(*p)->queue());
|
2007-07-20 01:07:30 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcReferenceQueue* q = (*p)->queue();
|
2007-07-20 01:07:30 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
if (q->front()) {
|
2014-06-26 01:42:16 +00:00
|
|
|
(*p)->setJNext(t, q->front());
|
2011-03-19 21:10:52 +00:00
|
|
|
} else {
|
2014-06-26 01:42:16 +00:00
|
|
|
(*p)->setJNext(t, *p);
|
2011-03-19 21:10:52 +00:00
|
|
|
}
|
2014-06-26 01:42:16 +00:00
|
|
|
q->setFront(t, *p);
|
2011-03-19 21:10:52 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
(*p)->queue() = 0;
|
2007-07-20 01:07:30 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
*p = cast<GcJreference>(t, (*p)->vmNext());
|
2007-07-20 01:07:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void referenceUnreachable(Thread* t, Heap::Visitor* v, GcJreference** p)
|
2007-07-20 03:18:25 +00:00
|
|
|
{
|
2014-06-29 05:48:17 +00:00
|
|
|
GcJreference* r = t->m->heap->follow(*p);
|
2009-09-02 00:32:21 +00:00
|
|
|
|
2007-07-29 23:32:23 +00:00
|
|
|
if (DebugReferences) {
|
2014-07-11 15:47:57 +00:00
|
|
|
fprintf(stderr, "reference %p unreachable (target %p)\n", *p, r->target());
|
2007-07-29 23:32:23 +00:00
|
|
|
}
|
2007-07-21 17:50:26 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
if (r->queue() and t->m->heap->status(r->queue()) != Heap::Unreachable) {
|
2007-07-20 03:18:25 +00:00
|
|
|
// queue is reachable - add the reference
|
2014-06-29 05:48:17 +00:00
|
|
|
referenceTargetUnreachable(t, v, p);
|
2007-07-29 23:32:23 +00:00
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
*p = cast<GcJreference>(t, (*p)->vmNext());
|
2007-07-20 03:18:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void referenceTargetReachable(Thread* t, Heap::Visitor* v, GcJreference** p)
|
2007-07-20 01:07:30 +00:00
|
|
|
{
|
2007-07-29 23:32:23 +00:00
|
|
|
if (DebugReferences) {
|
2014-07-11 15:47:57 +00:00
|
|
|
fprintf(
|
|
|
|
stderr, "target %p reachable for reference %p\n", (*p)->target(), *p);
|
2007-07-29 23:32:23 +00:00
|
|
|
}
|
2007-07-21 17:50:26 +00:00
|
|
|
|
2007-10-28 19:14:53 +00:00
|
|
|
v->visit(p);
|
2014-06-29 05:48:17 +00:00
|
|
|
v->visit(&(*p)->target());
|
2007-07-20 01:07:30 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
if (t->m->heap->status((*p)->queue()) == Heap::Unreachable) {
|
|
|
|
(*p)->queue() = 0;
|
2007-07-20 01:07:30 +00:00
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
v->visit(&(*p)->queue());
|
2007-07-20 01:07:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
bool isFinalizable(Thread* t, object o)
|
2012-10-05 16:06:01 +00:00
|
|
|
{
|
|
|
|
return t->m->heap->status(o) == Heap::Unreachable
|
2014-07-11 15:47:57 +00:00
|
|
|
and (t->m->heap->follow(objectClass(t, o))->vmFlags()
|
|
|
|
& HasFinalizerFlag);
|
2012-10-05 16:06:01 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void clearTargetIfFinalizable(Thread* t, GcJreference* r)
|
2012-10-05 16:06:01 +00:00
|
|
|
{
|
2014-07-11 15:47:57 +00:00
|
|
|
if (isFinalizable(t, t->m->heap->follow(r->target()))) {
|
2014-06-29 05:48:17 +00:00
|
|
|
r->target() = 0;
|
2012-10-05 16:06:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void postVisit(Thread* t, Heap::Visitor* v)
|
2007-07-10 01:43:43 +00:00
|
|
|
{
|
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
|
|
|
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, m->finalizeQueue == 0);
|
2007-07-29 23:32:23 +00:00
|
|
|
|
2012-10-05 16:06:01 +00:00
|
|
|
m->heap->postVisit();
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
for (GcJreference* p = m->weakReferences; p;) {
|
|
|
|
GcJreference* r = m->heap->follow(p);
|
|
|
|
p = cast<GcJreference>(t, r->vmNext());
|
2012-10-05 16:06:01 +00:00
|
|
|
clearTargetIfFinalizable(t, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (major) {
|
2014-06-29 05:48:17 +00:00
|
|
|
for (GcJreference* p = m->tenuredWeakReferences; p;) {
|
|
|
|
GcJreference* r = m->heap->follow(p);
|
|
|
|
p = cast<GcJreference>(t, r->vmNext());
|
2012-10-05 16:06:01 +00:00
|
|
|
clearTargetIfFinalizable(t, r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Reference* r = m->jniReferences; r; r = r->next) {
|
2014-07-11 15:50:18 +00:00
|
|
|
if (r->weak
|
|
|
|
and isFinalizable(t,
|
|
|
|
static_cast<object>(t->m->heap->follow(r->target)))) {
|
2012-10-05 16:06:01 +00:00
|
|
|
r->target = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcFinalizer* firstNewTenuredFinalizer = 0;
|
|
|
|
GcFinalizer* lastNewTenuredFinalizer = 0;
|
2007-07-10 01:43:43 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
{
|
|
|
|
object unreachable = 0;
|
2014-05-29 04:17:25 +00:00
|
|
|
for (GcFinalizer** p = &(m->finalizers); *p;) {
|
2013-03-08 03:17:05 +00:00
|
|
|
v->visit(p);
|
2007-07-10 01:43:43 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (m->heap->status((*p)->target()) == Heap::Unreachable) {
|
|
|
|
GcFinalizer* finalizer = *p;
|
|
|
|
*p = cast<GcFinalizer>(t, finalizer->next());
|
2013-03-08 03:17:05 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
finalizer->next() = unreachable;
|
2014-07-02 21:11:27 +00:00
|
|
|
unreachable = finalizer;
|
2013-03-08 03:17:05 +00:00
|
|
|
} else {
|
2014-05-29 04:17:25 +00:00
|
|
|
p = reinterpret_cast<GcFinalizer**>(&(*p)->next());
|
2013-03-08 03:17:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
for (GcFinalizer** p = &(m->finalizers); *p;) {
|
2007-07-10 01:43:43 +00:00
|
|
|
// target is reachable
|
2014-05-29 04:17:25 +00:00
|
|
|
v->visit(&(*p)->target());
|
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) {
|
2014-06-29 05:48:17 +00:00
|
|
|
lastNewTenuredFinalizer = *p;
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcFinalizer* finalizer = *p;
|
|
|
|
*p = cast<GcFinalizer>(t, finalizer->next());
|
2014-07-02 21:11:27 +00:00
|
|
|
finalizer->next() = firstNewTenuredFinalizer;
|
2014-06-29 05:48:17 +00:00
|
|
|
firstNewTenuredFinalizer = finalizer;
|
2007-07-10 01:43:43 +00:00
|
|
|
} else {
|
2014-05-29 04:17:25 +00:00
|
|
|
p = reinterpret_cast<GcFinalizer**>(&(*p)->next());
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
|
|
|
}
|
2013-03-08 03:17:05 +00:00
|
|
|
|
|
|
|
for (object* p = &unreachable; *p;) {
|
|
|
|
// target is unreachable - queue it up for finalization
|
2014-06-29 05:48:17 +00:00
|
|
|
finalizerTargetUnreachable(t, v, reinterpret_cast<GcFinalizer**>(p));
|
2013-03-08 03:17:05 +00:00
|
|
|
}
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcJreference* firstNewTenuredWeakReference = 0;
|
|
|
|
GcJreference* lastNewTenuredWeakReference = 0;
|
2007-07-10 01:43:43 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
for (GcJreference** p = &(m->weakReferences); *p;) {
|
2007-07-10 01:43:43 +00:00
|
|
|
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);
|
2014-07-11 15:47:57 +00:00
|
|
|
} else if (m->heap->status(m->heap->follow(*p)->target())
|
|
|
|
== 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;
|
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcJreference* reference = (*p);
|
|
|
|
*p = cast<GcJreference>(t, reference->vmNext());
|
2014-07-02 21:11:27 +00:00
|
|
|
reference->vmNext() = firstNewTenuredWeakReference;
|
2007-07-10 01:43:43 +00:00
|
|
|
firstNewTenuredWeakReference = reference;
|
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
p = reinterpret_cast<GcJreference**>(&(*p)->vmNext());
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-28 01:54:30 +00:00
|
|
|
if (major) {
|
2014-07-11 15:50:18 +00:00
|
|
|
{
|
|
|
|
object unreachable = 0;
|
2014-05-29 04:17:25 +00:00
|
|
|
for (GcFinalizer** p = &(m->tenuredFinalizers); *p;) {
|
2013-03-08 03:17:05 +00:00
|
|
|
v->visit(p);
|
2007-07-10 01:43:43 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (m->heap->status((*p)->target()) == Heap::Unreachable) {
|
|
|
|
GcFinalizer* finalizer = *p;
|
|
|
|
*p = cast<GcFinalizer>(t, finalizer->next());
|
2013-03-08 03:17:05 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
finalizer->next() = unreachable;
|
2014-07-02 21:11:27 +00:00
|
|
|
unreachable = finalizer;
|
2013-03-08 03:17:05 +00:00
|
|
|
} else {
|
2014-05-29 04:17:25 +00:00
|
|
|
p = reinterpret_cast<GcFinalizer**>(&(*p)->next());
|
2013-03-08 03:17:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
for (GcFinalizer** p = &(m->tenuredFinalizers); *p;) {
|
2007-07-10 01:43:43 +00:00
|
|
|
// target is reachable
|
2014-05-29 04:17:25 +00:00
|
|
|
v->visit(&(*p)->target());
|
|
|
|
p = reinterpret_cast<GcFinalizer**>(&(*p)->next());
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
2013-03-08 03:17:05 +00:00
|
|
|
|
|
|
|
for (object* p = &unreachable; *p;) {
|
|
|
|
// target is unreachable - queue it up for finalization
|
2014-06-29 05:48:17 +00:00
|
|
|
finalizerTargetUnreachable(t, v, reinterpret_cast<GcFinalizer**>(p));
|
2013-03-08 03:17:05 +00:00
|
|
|
}
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
for (GcJreference** p = &(m->tenuredWeakReferences); *p;) {
|
2007-07-10 01:43:43 +00:00
|
|
|
if (m->heap->status(*p) == Heap::Unreachable) {
|
2007-07-20 03:18:25 +00:00
|
|
|
// reference is unreachable
|
2014-06-29 05:48:17 +00:00
|
|
|
referenceUnreachable(t, v, reinterpret_cast<GcJreference**>(p));
|
2014-07-11 15:47:57 +00:00
|
|
|
} else if (m->heap->status(m->heap->follow(*p)->target())
|
|
|
|
== Heap::Unreachable) {
|
2007-07-20 03:18:25 +00:00
|
|
|
// target is unreachable
|
2014-06-29 05:48:17 +00:00
|
|
|
referenceTargetUnreachable(t, v, reinterpret_cast<GcJreference**>(p));
|
2007-07-10 01:43:43 +00:00
|
|
|
} else {
|
2007-07-20 03:18:25 +00:00
|
|
|
// both reference and target are reachable
|
2014-06-29 05:48:17 +00:00
|
|
|
referenceTargetReachable(t, v, reinterpret_cast<GcJreference**>(p));
|
|
|
|
p = reinterpret_cast<GcJreference**>(&(*p)->vmNext());
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lastNewTenuredFinalizer) {
|
2014-07-02 21:11:27 +00:00
|
|
|
lastNewTenuredFinalizer->next() = m->tenuredFinalizers;
|
2014-06-29 05:48:17 +00:00
|
|
|
m->tenuredFinalizers = firstNewTenuredFinalizer;
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (lastNewTenuredWeakReference) {
|
2014-07-11 15:47:57 +00:00
|
|
|
lastNewTenuredWeakReference->vmNext() = m->tenuredWeakReferences;
|
2014-06-29 05:48:17 +00:00
|
|
|
m->tenuredWeakReferences = firstNewTenuredWeakReference;
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
2012-02-29 18:51:30 +00:00
|
|
|
|
|
|
|
for (Reference* r = m->jniReferences; r; r = r->next) {
|
|
|
|
if (r->weak) {
|
|
|
|
if (m->heap->status(r->target) == Heap::Unreachable) {
|
|
|
|
r->target = 0;
|
|
|
|
} else {
|
|
|
|
v->visit(&(r->target));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-07-10 01:43:43 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void postCollect(Thread* t)
|
2007-07-07 23:47:35 +00:00
|
|
|
{
|
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);
|
2014-07-11 15:50:18 +00:00
|
|
|
t->defaultHeap
|
|
|
|
= static_cast<uintptr_t*>(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
|
|
|
|
2014-08-20 15:49:00 +00:00
|
|
|
if (t->getFlags() & Thread::UseBackupHeapFlag) {
|
2010-06-19 22:40:21 +00:00
|
|
|
memset(t->backupHeap, 0, ThreadBackupHeapSizeInBytes);
|
|
|
|
|
2014-08-20 15:49:00 +00:00
|
|
|
t->clearFlag(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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
uint64_t invoke(Thread* t, uintptr_t* arguments)
|
2010-12-27 22:55:23 +00:00
|
|
|
{
|
2014-05-29 04:17:25 +00:00
|
|
|
GcMethod* m = cast<GcMethod>(t, *reinterpret_cast<object*>(arguments[0]));
|
2011-03-17 14:49:41 +00:00
|
|
|
object o = *reinterpret_cast<object*>(arguments[1]);
|
2010-12-27 22:55:23 +00:00
|
|
|
|
|
|
|
t->m->processor->invoke(t, m, o);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void finalizeObject(Thread* t, object o, const char* name)
|
2009-07-22 00:57:55 +00:00
|
|
|
{
|
2014-06-21 04:16:33 +00:00
|
|
|
for (GcClass* c = objectClass(t, o); c; c = c->super()) {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* mtable = cast<GcArray>(t, c->methodTable());
|
|
|
|
for (unsigned i = 0; i < mtable->length(); ++i) {
|
|
|
|
GcMethod* m = cast<GcMethod>(t, mtable->body()[i]);
|
2009-07-22 00:57:55 +00:00
|
|
|
|
2011-03-19 21:10:52 +00:00
|
|
|
if (vm::strcmp(reinterpret_cast<const int8_t*>(name),
|
2014-06-29 05:48:17 +00:00
|
|
|
m->name()->body().begin()) == 0
|
2009-08-27 00:26:44 +00:00
|
|
|
and vm::strcmp(reinterpret_cast<const int8_t*>("()V"),
|
2014-07-11 15:47:57 +00:00
|
|
|
m->spec()->body().begin()) == 0) {
|
2011-03-17 14:49:41 +00:00
|
|
|
PROTECT(t, m);
|
|
|
|
PROTECT(t, o);
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
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;
|
2014-06-29 05:48:17 +00:00
|
|
|
}
|
2009-07-22 00:57:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
unsigned readByte(AbstractStream& s, unsigned* value)
|
2009-08-14 14:52:31 +00:00
|
|
|
{
|
|
|
|
if (*value == NoByte) {
|
|
|
|
return s.read1();
|
|
|
|
} else {
|
|
|
|
unsigned r = *value;
|
|
|
|
*value = NoByte;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcCharArray* parseUtf8NonAscii(Thread* t,
|
|
|
|
AbstractStream& s,
|
|
|
|
GcByteArray* bytesSoFar,
|
|
|
|
unsigned byteCount,
|
|
|
|
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);
|
2014-06-29 05:48:17 +00:00
|
|
|
|
|
|
|
unsigned length = bytesSoFar->length() - 1;
|
|
|
|
GcCharArray* value = makeCharArray(t, length + 1);
|
2009-06-04 23:21:42 +00:00
|
|
|
|
2007-10-24 21:05:15 +00:00
|
|
|
unsigned vi = 0;
|
2009-06-04 23:21:42 +00:00
|
|
|
for (; vi < byteCount; ++vi) {
|
2014-06-29 05:48:17 +00:00
|
|
|
value->body()[vi] = bytesSoFar->body()[vi];
|
2009-06-04 23:21:42 +00:00
|
|
|
}
|
|
|
|
|
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) {
|
2014-06-29 05:48:17 +00:00
|
|
|
// 3 bytes
|
|
|
|
si += 2;
|
|
|
|
assertT(t, si < length);
|
2009-08-14 14:52:31 +00:00
|
|
|
unsigned b = readByte(s, &byteB);
|
2014-06-29 05:48:17 +00:00
|
|
|
unsigned c = s.read1();
|
|
|
|
value->body()[vi++] = ((a & 0xf) << 12) | ((b & 0x3f) << 6)
|
2014-07-11 15:47:57 +00:00
|
|
|
| (c & 0x3f);
|
2007-10-24 21:05:15 +00:00
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
// 2 bytes
|
|
|
|
++si;
|
|
|
|
assertT(t, si < length);
|
2009-08-14 14:52:31 +00:00
|
|
|
unsigned b = readByte(s, &byteB);
|
2007-10-25 23:58:53 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
if (a == 0xC0 and b == 0x80) {
|
|
|
|
value->body()[vi++] = 0;
|
|
|
|
} else {
|
|
|
|
value->body()[vi++] = ((a & 0x1f) << 6) | (b & 0x3f);
|
|
|
|
}
|
2009-06-04 23:21:42 +00:00
|
|
|
}
|
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
value->body()[vi++] = a;
|
2009-06-04 23:21:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vi < length) {
|
|
|
|
PROTECT(t, value);
|
2014-06-29 05:48:17 +00:00
|
|
|
|
|
|
|
GcCharArray* v = makeCharArray(t, vi + 1);
|
|
|
|
memcpy(v->body().begin(), value->body().begin(), vi * 2);
|
2009-06-04 23:21:42 +00:00
|
|
|
value = v;
|
|
|
|
}
|
2014-06-29 05:48:17 +00:00
|
|
|
|
2009-06-04 23:21:42 +00:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
object parseUtf8(Thread* t, AbstractStream& s, unsigned length)
|
2009-06-04 23:21:42 +00:00
|
|
|
{
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* value = makeByteArray(t, length + 1);
|
2009-06-04 23:21:42 +00:00
|
|
|
unsigned vi = 0;
|
|
|
|
for (unsigned si = 0; si < length; ++si) {
|
|
|
|
unsigned a = s.read1();
|
|
|
|
if (a & 0x80) {
|
|
|
|
if (a & 0x20) {
|
2014-06-29 05:48:17 +00:00
|
|
|
// 3 bytes
|
2014-07-02 21:11:27 +00:00
|
|
|
return parseUtf8NonAscii(t, s, value, vi, si, a, NoByte);
|
2009-06-04 23:21:42 +00:00
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
// 2 bytes
|
|
|
|
unsigned b = s.read1();
|
2009-06-04 23:21:42 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
if (a == 0xC0 and b == 0x80) {
|
|
|
|
++si;
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, si < length);
|
2014-06-29 05:48:17 +00:00
|
|
|
value->body()[vi++] = 0;
|
|
|
|
} else {
|
2014-07-02 21:11:27 +00:00
|
|
|
return parseUtf8NonAscii(t, s, value, vi, si, a, b);
|
2014-06-29 05:48:17 +00:00
|
|
|
}
|
2007-10-24 21:05:15 +00:00
|
|
|
}
|
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
value->body()[vi++] = a;
|
2007-10-24 21:05:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (vi < length) {
|
|
|
|
PROTECT(t, value);
|
2014-06-29 05:48:17 +00:00
|
|
|
|
|
|
|
GcByteArray* v = makeByteArray(t, vi + 1);
|
|
|
|
memcpy(v->body().begin(), value->body().begin(), vi);
|
2007-10-24 21:05:15 +00:00
|
|
|
value = v;
|
|
|
|
}
|
2014-06-29 05:48:17 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
return value;
|
2007-10-24 21:05:15 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcByteArray* makeByteArray(Thread* t, Stream& s, unsigned length)
|
2013-02-03 21:09:29 +00:00
|
|
|
{
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* value = makeByteArray(t, length + 1);
|
|
|
|
s.read(reinterpret_cast<uint8_t*>(value->body().begin()), length);
|
2013-02-03 21:09:29 +00:00
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void removeByteArray(Thread* t, object o)
|
2009-06-07 00:26:23 +00:00
|
|
|
{
|
2014-07-11 15:47:57 +00:00
|
|
|
hashMapRemove(t, roots(t)->byteArrayMap(), o, byteArrayHash, objectEqual);
|
2009-06-07 00:26:23 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcByteArray* internByteArray(Thread* t, GcByteArray* array)
|
2009-06-07 00:26:23 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, array);
|
|
|
|
|
2010-09-17 01:43:27 +00:00
|
|
|
ACQUIRE(t, t->m->referenceLock);
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcTriple* n = hashMapFindNode(
|
|
|
|
t, roots(t)->byteArrayMap(), array, byteArrayHash, byteArrayEqual);
|
2009-06-07 00:26:23 +00:00
|
|
|
if (n) {
|
2014-06-29 05:48:17 +00:00
|
|
|
return cast<GcByteArray>(t, cast<GcJreference>(t, n->first())->target());
|
2009-06-07 00:26:23 +00:00
|
|
|
} else {
|
2014-07-02 21:11:27 +00:00
|
|
|
hashMapInsert(t, roots(t)->byteArrayMap(), array, 0, byteArrayHash);
|
|
|
|
addFinalizer(t, array, removeByteArray);
|
2009-06-07 00:26:23 +00:00
|
|
|
return array;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
unsigned parsePoolEntry(Thread* t,
|
|
|
|
Stream& s,
|
|
|
|
uint32_t* index,
|
|
|
|
GcSingleton* 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: {
|
2012-05-22 19:53:32 +00:00
|
|
|
uint32_t v = s.read4();
|
|
|
|
singletonValue(t, pool, i) = v;
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (DebugClassReader) {
|
2012-05-22 19:53:32 +00:00
|
|
|
fprintf(stderr, " consts[%d] = int/float 0x%x\n", i, v);
|
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
case CONSTANT_Long:
|
|
|
|
case CONSTANT_Double: {
|
|
|
|
uint64_t v = s.read8();
|
|
|
|
memcpy(&singletonValue(t, pool, i), &v, 8);
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (DebugClassReader) {
|
2012-05-22 19:53:32 +00:00
|
|
|
fprintf(stderr, " consts[%d] = long/double <todo>\n", i);
|
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
}
|
|
|
|
return 2;
|
2007-11-05 21:40:17 +00:00
|
|
|
|
|
|
|
case CONSTANT_Utf8: {
|
|
|
|
if (singletonObject(t, pool, i) == 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* value = internByteArray(t, makeByteArray(t, s, s.read2()));
|
2014-06-26 01:42:16 +00:00
|
|
|
pool->setBodyElement(t, i, reinterpret_cast<uintptr_t>(value));
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (DebugClassReader) {
|
2014-06-29 05:48:17 +00:00
|
|
|
fprintf(stderr, " consts[%d] = utf8 %s\n", i, value->body().begin());
|
2012-05-22 19:53:32 +00:00
|
|
|
}
|
2007-11-05 21:40:17 +00:00
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
}
|
|
|
|
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);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
|
|
|
GcReference* value = makeReference(
|
|
|
|
t, 0, 0, cast<GcByteArray>(t, singletonObject(t, pool, si)), 0);
|
2014-06-26 01:42:16 +00:00
|
|
|
pool->setBodyElement(t, i, reinterpret_cast<uintptr_t>(value));
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (DebugClassReader) {
|
2012-05-22 19:53:32 +00:00
|
|
|
fprintf(stderr, " consts[%d] = class <todo>\n", i);
|
|
|
|
}
|
2007-11-05 21:40:17 +00:00
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
}
|
|
|
|
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);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
|
|
|
object value
|
|
|
|
= parseUtf8(t, cast<GcByteArray>(t, singletonObject(t, pool, si)));
|
2014-07-11 15:50:18 +00:00
|
|
|
value = t->m->classpath->makeString(
|
|
|
|
t, value, 0, fieldAtOffset<uintptr_t>(value, BytesPerWord) - 1);
|
2007-11-05 21:40:17 +00:00
|
|
|
value = intern(t, value);
|
2014-06-26 01:42:16 +00:00
|
|
|
pool->setBodyElement(t, i, reinterpret_cast<uintptr_t>(value));
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (DebugClassReader) {
|
2012-05-22 19:53:32 +00:00
|
|
|
fprintf(stderr, " consts[%d] = string <todo>\n", i);
|
|
|
|
}
|
2007-11-05 21:40:17 +00:00
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
}
|
|
|
|
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);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* name = cast<GcByteArray>(t, singletonObject(t, pool, ni));
|
|
|
|
GcByteArray* type = cast<GcByteArray>(t, singletonObject(t, pool, ti));
|
2014-07-02 21:11:27 +00:00
|
|
|
GcPair* value = makePair(t, name, type);
|
2014-06-26 01:42:16 +00:00
|
|
|
pool->setBodyElement(t, i, reinterpret_cast<uintptr_t>(value));
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (DebugClassReader) {
|
2014-07-11 15:47:57 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
" consts[%d] = nameAndType %s%s\n",
|
|
|
|
i,
|
|
|
|
name->body().begin(),
|
|
|
|
type->body().begin());
|
2012-05-22 19:53:32 +00:00
|
|
|
}
|
2007-11-05 21:40:17 +00:00
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
}
|
|
|
|
return 1;
|
2007-11-05 21:40:17 +00:00
|
|
|
|
|
|
|
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);
|
2012-02-28 01:16:01 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcByteArray* className
|
|
|
|
= cast<GcReference>(t, singletonObject(t, pool, ci))->name();
|
2014-06-29 05:48:17 +00:00
|
|
|
GcPair* nameAndType = cast<GcPair>(t, singletonObject(t, pool, nti));
|
2012-02-28 01:16:01 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
object value = makeReference(t,
|
|
|
|
0,
|
|
|
|
className,
|
|
|
|
cast<GcByteArray>(t, nameAndType->first()),
|
|
|
|
cast<GcByteArray>(t, nameAndType->second()));
|
2014-06-26 01:42:16 +00:00
|
|
|
pool->setBodyElement(t, i, reinterpret_cast<uintptr_t>(value));
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (DebugClassReader) {
|
2014-06-29 05:48:17 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
" consts[%d] = method %s.%s%s\n",
|
|
|
|
i,
|
|
|
|
className->body().begin(),
|
|
|
|
cast<GcByteArray>(t, nameAndType->first())->body().begin(),
|
|
|
|
cast<GcByteArray>(t, nameAndType->second())->body().begin());
|
2012-05-22 19:53:32 +00:00
|
|
|
}
|
2007-11-05 21:40:17 +00:00
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
}
|
|
|
|
return 1;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-04-23 21:22:10 +00:00
|
|
|
case CONSTANT_MethodHandle:
|
|
|
|
if (singletonObject(t, pool, i) == 0) {
|
|
|
|
unsigned kind = s.read1();
|
|
|
|
unsigned ri = s.read2() - 1;
|
|
|
|
|
|
|
|
parsePoolEntry(t, s, index, pool, ri);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcReference* value = cast<GcReference>(t, singletonObject(t, pool, ri));
|
2014-04-23 21:22:10 +00:00
|
|
|
|
|
|
|
if (DebugClassReader) {
|
2014-07-11 15:47:57 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
" consts[%d] = method handle %d %s.%s%s\n",
|
|
|
|
i,
|
|
|
|
kind,
|
2014-06-29 05:48:17 +00:00
|
|
|
value->class_()->body().begin(),
|
|
|
|
value->name()->body().begin(),
|
|
|
|
value->spec()->body().begin());
|
2014-04-23 21:22:10 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
value = makeReference(
|
|
|
|
t, kind, value->class_(), value->name(), value->spec());
|
2014-04-23 21:22:10 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
pool->setBodyElement(t, i, reinterpret_cast<uintptr_t>(value));
|
2014-07-11 15:50:18 +00:00
|
|
|
}
|
|
|
|
return 1;
|
2014-04-23 21:22:10 +00:00
|
|
|
|
|
|
|
case CONSTANT_MethodType:
|
|
|
|
if (singletonObject(t, pool, i) == 0) {
|
|
|
|
unsigned ni = s.read2() - 1;
|
|
|
|
|
|
|
|
parsePoolEntry(t, s, index, pool, ni);
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
pool->setBodyElement(
|
|
|
|
t, i, reinterpret_cast<uintptr_t>(singletonObject(t, pool, ni)));
|
2014-07-11 15:50:18 +00:00
|
|
|
}
|
|
|
|
return 1;
|
2014-04-23 21:22:10 +00:00
|
|
|
|
|
|
|
case CONSTANT_InvokeDynamic:
|
|
|
|
if (singletonObject(t, pool, i) == 0) {
|
|
|
|
unsigned bootstrap = s.read2();
|
|
|
|
unsigned nti = s.read2() - 1;
|
|
|
|
|
|
|
|
parsePoolEntry(t, s, index, pool, nti);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcPair* nameAndType = cast<GcPair>(t, singletonObject(t, pool, nti));
|
2014-04-23 21:22:10 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
const char* specString = reinterpret_cast<const char*>(
|
|
|
|
cast<GcByteArray>(t, nameAndType->second())->body().begin());
|
2014-04-23 21:22:10 +00:00
|
|
|
|
|
|
|
unsigned parameterCount;
|
|
|
|
unsigned parameterFootprint;
|
|
|
|
unsigned returnCode;
|
2014-07-11 15:50:18 +00:00
|
|
|
scanMethodSpec(t,
|
|
|
|
specString,
|
|
|
|
true,
|
|
|
|
¶meterCount,
|
|
|
|
¶meterFootprint,
|
|
|
|
&returnCode);
|
2014-04-23 21:22:10 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcMethod* template_
|
|
|
|
= makeMethod(t,
|
|
|
|
0,
|
|
|
|
returnCode,
|
|
|
|
parameterCount,
|
|
|
|
parameterFootprint,
|
2016-12-07 17:23:13 +00:00
|
|
|
ACC_STATIC,
|
2014-07-11 15:47:57 +00:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
cast<GcByteArray>(t, nameAndType->first()),
|
|
|
|
cast<GcByteArray>(t, nameAndType->second()),
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0);
|
|
|
|
|
|
|
|
object value = reinterpret_cast<object>(
|
|
|
|
makeInvocation(t, bootstrap, -1, 0, pool, template_, 0));
|
2014-04-23 21:22:10 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
pool->setBodyElement(t, i, reinterpret_cast<uintptr_t>(value));
|
2014-07-11 15:50:18 +00:00
|
|
|
}
|
|
|
|
return 1;
|
2014-04-23 21:22:10 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
default:
|
|
|
|
abort(t);
|
2007-11-05 21:40:17 +00:00
|
|
|
}
|
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcSingleton* parsePool(Thread* t, Stream& s)
|
2007-11-05 21:40:17 +00:00
|
|
|
{
|
|
|
|
unsigned count = s.read2() - 1;
|
2014-05-29 04:17:25 +00:00
|
|
|
GcSingleton* 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
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (DebugClassReader) {
|
2012-05-22 19:53:32 +00:00
|
|
|
fprintf(stderr, " const pool entries %d\n", count);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
THREAD_RESOURCE2(t,
|
|
|
|
uint32_t*,
|
|
|
|
index,
|
|
|
|
unsigned,
|
|
|
|
count,
|
2010-12-27 22:55:23 +00:00
|
|
|
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);
|
2014-07-11 15:50:18 +00:00
|
|
|
++i;
|
2009-08-10 19:20:23 +00:00
|
|
|
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);
|
2014-07-11 15:50:18 +00:00
|
|
|
++i;
|
2007-11-05 21:40:17 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CONSTANT_Utf8:
|
|
|
|
singletonMarkObject(t, pool, i);
|
|
|
|
s.skip(s.read2());
|
|
|
|
break;
|
|
|
|
|
2014-04-23 21:22:10 +00:00
|
|
|
case CONSTANT_MethodHandle:
|
|
|
|
singletonMarkObject(t, pool, i);
|
|
|
|
s.skip(3);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CONSTANT_MethodType:
|
|
|
|
singletonMarkObject(t, pool, i);
|
|
|
|
s.skip(2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CONSTANT_InvokeDynamic:
|
|
|
|
singletonMarkObject(t, pool, i);
|
|
|
|
s.skip(4);
|
|
|
|
break;
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void addInterfaces(Thread* t, GcClass* class_, GcHashMap* map)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* table = cast<GcArray>(t, class_->interfaceTable());
|
2007-07-14 17:31:01 +00:00
|
|
|
if (table) {
|
|
|
|
unsigned increment = 2;
|
2014-05-29 04:17:25 +00:00
|
|
|
if (class_->flags() & ACC_INTERFACE) {
|
2007-07-14 17:31:01 +00:00
|
|
|
increment = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PROTECT(t, map);
|
|
|
|
PROTECT(t, table);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
for (unsigned i = 0; i < table->length(); i += increment) {
|
|
|
|
GcClass* interface = cast<GcClass>(t, table->body()[i]);
|
2014-06-21 04:16:33 +00:00
|
|
|
GcByteArray* name = interface->name();
|
2014-07-11 15:47:57 +00:00
|
|
|
hashMapInsertMaybe(
|
|
|
|
t, map, name, interface, byteArrayHash, byteArrayEqual);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClassAddendum* getClassAddendum(Thread* t, GcClass* class_, GcSingleton* pool)
|
2011-04-10 03:20:56 +00:00
|
|
|
{
|
2014-06-21 04:16:33 +00:00
|
|
|
GcClassAddendum* addendum = class_->addendum();
|
2011-04-10 03:20:56 +00:00
|
|
|
if (addendum == 0) {
|
2011-07-10 00:01:00 +00:00
|
|
|
PROTECT(t, class_);
|
|
|
|
|
2016-12-06 00:41:02 +00:00
|
|
|
addendum = makeClassAddendum(t, pool, 0, 0, 0, 0, -1, 0, 0, 0, 0);
|
2014-07-11 15:47:57 +00:00
|
|
|
setField(t, class_, ClassAddendum, addendum);
|
2011-04-10 03:20:56 +00:00
|
|
|
}
|
|
|
|
return addendum;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void parseInterfaceTable(Thread* t,
|
|
|
|
Stream& s,
|
|
|
|
GcClass* class_,
|
|
|
|
GcSingleton* pool,
|
|
|
|
Gc::Type throwType)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, class_);
|
|
|
|
PROTECT(t, pool);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcHashMap* map = makeHashMap(t, 0, 0);
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, map);
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (class_->super()) {
|
2014-06-21 04:16:33 +00:00
|
|
|
addInterfaces(t, class_->super(), map);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
2007-11-27 22:23:00 +00:00
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned count = s.read2();
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* table = 0;
|
2011-03-28 02:29:31 +00:00
|
|
|
PROTECT(t, table);
|
|
|
|
|
|
|
|
if (count) {
|
2014-06-29 05:48:17 +00:00
|
|
|
table = makeArray(t, count);
|
2011-04-10 03:20:56 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcClassAddendum* addendum = getClassAddendum(t, class_, pool);
|
2014-07-02 21:11:27 +00:00
|
|
|
addendum->setInterfaceTable(t, table);
|
2011-03-28 02:29:31 +00:00
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
2014-07-11 15:47:57 +00:00
|
|
|
GcByteArray* name
|
|
|
|
= cast<GcReference>(t, singletonObject(t, pool, s.read2() - 1))->name();
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, name);
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* interface = resolveClass(
|
|
|
|
t, class_->loader(), name, true, throwType);
|
2009-08-04 14:50:04 +00:00
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, interface);
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
table->setBodyElement(t, i, interface);
|
2011-03-28 02:29:31 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
hashMapInsertMaybe(t, map, name, interface, byteArrayHash, byteArrayEqual);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
|
|
|
addInterfaces(t, interface, map);
|
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* interfaceTable = 0;
|
2014-05-29 04:17:25 +00:00
|
|
|
if (map->size()) {
|
|
|
|
unsigned length = map->size();
|
|
|
|
if ((class_->flags() & ACC_INTERFACE) == 0) {
|
2007-07-14 17:31:01 +00:00
|
|
|
length *= 2;
|
|
|
|
}
|
2014-06-29 05:48:17 +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();) {
|
2014-06-28 20:41:27 +00:00
|
|
|
GcClass* interface = cast<GcClass>(t, it.next()->second());
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
interfaceTable->setBodyElement(t, i, interface);
|
2014-07-11 15:50:18 +00:00
|
|
|
++i;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if ((class_->flags() & ACC_INTERFACE) == 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
if (GcArray* vt = cast<GcArray>(t, interface->virtualTable())) {
|
|
|
|
PROTECT(t, vt);
|
2007-08-14 00:37:00 +00:00
|
|
|
// we'll fill in this table in parseMethodTable():
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* vtable = makeArray(t, vt->length());
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
interfaceTable->setBodyElement(t, i, vtable);
|
2007-08-14 00:37:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
++i;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
class_->setInterfaceTable(t, interfaceTable);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void parseFieldTable(Thread* t, Stream& s, GcClass* class_, GcSingleton* pool)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, class_);
|
|
|
|
PROTECT(t, pool);
|
|
|
|
|
|
|
|
unsigned memberOffset = BytesPerWord;
|
2014-05-29 04:17:25 +00:00
|
|
|
if (class_->super()) {
|
2014-06-21 04:16:33 +00:00
|
|
|
memberOffset = class_->super()->fixedSize();
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned count = s.read2();
|
|
|
|
if (count) {
|
2012-09-12 01:21:51 +00:00
|
|
|
unsigned staticOffset = BytesPerWord * 3;
|
2007-11-02 21:08:14 +00:00
|
|
|
unsigned staticCount = 0;
|
2014-07-11 15:47:57 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* fieldTable = makeArray(t, count);
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, fieldTable);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcIntArray* staticValueTable = makeIntArray(t, count);
|
2007-10-25 19:20:39 +00:00
|
|
|
PROTECT(t, staticValueTable);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcFieldAddendum* addendum = 0;
|
2009-09-19 00:01:54 +00:00
|
|
|
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;
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
unsigned code = fieldCode(
|
|
|
|
t,
|
|
|
|
cast<GcByteArray>(t, singletonObject(t, pool, spec - 1))->body()[0]);
|
2007-11-05 21:40:17 +00:00
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned attributeCount = s.read2();
|
|
|
|
for (unsigned j = 0; j < attributeCount; ++j) {
|
2014-07-11 15:47:57 +00:00
|
|
|
GcByteArray* name
|
|
|
|
= cast<GcByteArray>(t, 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"),
|
2014-07-11 15:47:57 +00:00
|
|
|
name->body().begin()) == 0) {
|
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"),
|
2014-07-11 15:47:57 +00:00
|
|
|
name->body().begin()) == 0) {
|
2011-03-18 03:42:15 +00:00
|
|
|
if (addendum == 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
addendum = makeFieldAddendum(t, pool, 0, 0);
|
2011-03-18 03:42:15 +00:00
|
|
|
}
|
2014-06-29 05:48:17 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
addendum->setSignature(t, singletonObject(t, pool, s.read2() - 1));
|
2014-07-11 15:47:57 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>(
|
|
|
|
"RuntimeVisibleAnnotations"),
|
|
|
|
name->body().begin()) == 0) {
|
2011-03-18 03:42:15 +00:00
|
|
|
if (addendum == 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
addendum = makeFieldAddendum(t, pool, 0, 0);
|
2011-03-18 03:42:15 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* body = makeByteArray(t, length);
|
2014-07-11 15:47:57 +00:00
|
|
|
s.read(reinterpret_cast<uint8_t*>(body->body().begin()), length);
|
2011-03-18 03:42:15 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
addendum->setAnnotationTable(t, body);
|
2007-10-25 19:20:39 +00:00
|
|
|
} else {
|
|
|
|
s.skip(length);
|
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcField* field
|
|
|
|
= makeField(t,
|
|
|
|
0, // vm flags
|
|
|
|
code,
|
|
|
|
flags,
|
|
|
|
0, // offset
|
|
|
|
0, // native ID
|
|
|
|
cast<GcByteArray>(t, singletonObject(t, pool, name - 1)),
|
|
|
|
cast<GcByteArray>(t, singletonObject(t, pool, spec - 1)),
|
|
|
|
addendum,
|
|
|
|
class_);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
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) {
|
2014-01-06 22:19:00 +00:00
|
|
|
staticOffset = pad(staticOffset, size);
|
2007-11-02 21:08:14 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
field->offset() = staticOffset;
|
2007-11-02 21:08:14 +00:00
|
|
|
|
|
|
|
staticOffset += size;
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
staticValueTable->body()[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) {
|
2014-05-29 04:17:25 +00:00
|
|
|
class_->vmFlags() |= HasFinalMemberFlag;
|
2009-03-03 03:18:15 +00:00
|
|
|
}
|
|
|
|
|
2014-01-06 22:19:00 +00:00
|
|
|
memberOffset = pad(memberOffset, size);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
field->offset() = memberOffset;
|
2011-08-30 01:00:17 +00:00
|
|
|
|
|
|
|
memberOffset += size;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
fieldTable->setBodyElement(t, i, field);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
class_->setFieldTable(t, fieldTable);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-11-02 21:08:14 +00:00
|
|
|
if (staticCount) {
|
2014-07-11 15:50:18 +00:00
|
|
|
unsigned footprint
|
|
|
|
= ceilingDivide(staticOffset - (BytesPerWord * 2), BytesPerWord);
|
2014-05-29 04:17:25 +00:00
|
|
|
GcSingleton* staticTable = makeSingletonOfSize(t, footprint);
|
2007-11-02 21:08:14 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
uint8_t* body = reinterpret_cast<uint8_t*>(staticTable->body().begin());
|
2007-11-02 21:08:14 +00:00
|
|
|
|
2012-09-12 01:21:51 +00:00
|
|
|
memcpy(body, &class_, BytesPerWord);
|
|
|
|
singletonMarkObject(t, staticTable, 0);
|
|
|
|
|
|
|
|
for (unsigned i = 0, offset = BytesPerWord; i < staticCount; ++i) {
|
2009-08-27 00:26:44 +00:00
|
|
|
unsigned size = fieldSize(t, RUNTIME_ARRAY_BODY(staticTypes)[i]);
|
2014-01-06 22:19:00 +00:00
|
|
|
offset = pad(offset, size);
|
2007-11-02 21:08:14 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
unsigned value = staticValueTable->body()[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)
|
2014-07-11 15:50:18 +00:00
|
|
|
= 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)
|
2014-07-11 15:50:18 +00:00
|
|
|
= 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;
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
default:
|
|
|
|
abort(t);
|
2007-11-02 21:08:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
class_->setStaticTable(t, staticTable);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-21 04:16:33 +00:00
|
|
|
class_->fixedSize() = memberOffset;
|
2014-07-11 15:47:57 +00:00
|
|
|
|
|
|
|
if (class_->super() and memberOffset == class_->super()->fixedSize()) {
|
|
|
|
class_->setObjectMask(t, class_->super()->objectMask());
|
2007-07-14 17:31:01 +00:00
|
|
|
} else {
|
2014-07-11 15:47:57 +00:00
|
|
|
GcIntArray* mask = makeIntArray(
|
|
|
|
t, ceilingDivide(class_->fixedSize(), 32 * BytesPerWord));
|
2014-06-29 05:48:17 +00:00
|
|
|
mask->body()[0] = 1;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcIntArray* superMask = 0;
|
2014-05-29 04:17:25 +00:00
|
|
|
if (class_->super()) {
|
2014-06-29 05:48:17 +00:00
|
|
|
superMask = class_->super()->objectMask();
|
2007-08-14 00:37:00 +00:00
|
|
|
if (superMask) {
|
2014-07-11 15:47:57 +00:00
|
|
|
memcpy(
|
|
|
|
mask->body().begin(),
|
|
|
|
superMask->body().begin(),
|
|
|
|
ceilingDivide(class_->super()->fixedSize(), 32 * BytesPerWord) * 4);
|
2007-08-14 00:37:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
bool sawReferenceField = false;
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* fieldTable = cast<GcArray>(t, class_->fieldTable());
|
2007-08-14 00:37:00 +00:00
|
|
|
if (fieldTable) {
|
2014-06-29 05:48:17 +00:00
|
|
|
for (int i = fieldTable->length() - 1; i >= 0; --i) {
|
|
|
|
GcField* field = cast<GcField>(t, fieldTable->body()[i]);
|
|
|
|
if ((field->flags() & ACC_STATIC) == 0
|
2014-07-11 15:47:57 +00:00
|
|
|
and field->code() == ObjectField) {
|
2014-06-29 05:48:17 +00:00
|
|
|
unsigned index = field->offset() / BytesPerWord;
|
|
|
|
mask->body()[index / 32] |= 1 << (index % 32);
|
2007-08-14 00:37:00 +00:00
|
|
|
sawReferenceField = true;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-14 00:37:00 +00:00
|
|
|
if (superMask or sawReferenceField) {
|
2014-06-26 01:42:16 +00:00
|
|
|
class_->setObjectMask(t, mask);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
uint16_t read16(uint8_t* code, unsigned& ip)
|
|
|
|
{
|
2012-05-22 19:53:32 +00:00
|
|
|
uint16_t a = code[ip++];
|
|
|
|
uint16_t b = code[ip++];
|
|
|
|
return (a << 8) | b;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
uint32_t read32(uint8_t* code, unsigned& ip)
|
|
|
|
{
|
2012-05-22 19:53:32 +00:00
|
|
|
uint32_t b = code[ip++];
|
|
|
|
uint32_t a = code[ip++];
|
|
|
|
uint32_t c = code[ip++];
|
|
|
|
uint32_t d = code[ip++];
|
|
|
|
return (a << 24) | (b << 16) | (c << 8) | d;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void disassembleCode(const char* prefix, uint8_t* code, unsigned length)
|
2012-05-22 19:53:32 +00:00
|
|
|
{
|
|
|
|
unsigned ip = 0;
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
while (ip < length) {
|
2012-05-22 19:53:32 +00:00
|
|
|
unsigned instr;
|
|
|
|
fprintf(stderr, "%s%x:\t", prefix, ip);
|
|
|
|
switch (instr = code[ip++]) {
|
2014-07-11 15:50:18 +00:00
|
|
|
case aaload:
|
|
|
|
fprintf(stderr, "aaload\n");
|
|
|
|
break;
|
|
|
|
case aastore:
|
|
|
|
fprintf(stderr, "aastore\n");
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case aconst_null:
|
|
|
|
fprintf(stderr, "aconst_null\n");
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case aload:
|
|
|
|
fprintf(stderr, "aload %02x\n", code[ip++]);
|
|
|
|
break;
|
|
|
|
case aload_0:
|
|
|
|
fprintf(stderr, "aload_0\n");
|
|
|
|
break;
|
|
|
|
case aload_1:
|
|
|
|
fprintf(stderr, "aload_1\n");
|
|
|
|
break;
|
|
|
|
case aload_2:
|
|
|
|
fprintf(stderr, "aload_2\n");
|
|
|
|
break;
|
|
|
|
case aload_3:
|
|
|
|
fprintf(stderr, "aload_3\n");
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case anewarray:
|
|
|
|
fprintf(stderr, "anewarray %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case areturn:
|
|
|
|
fprintf(stderr, "areturn\n");
|
|
|
|
break;
|
|
|
|
case arraylength:
|
|
|
|
fprintf(stderr, "arraylength\n");
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case astore:
|
|
|
|
fprintf(stderr, "astore %02x\n", code[ip++]);
|
|
|
|
break;
|
|
|
|
case astore_0:
|
|
|
|
fprintf(stderr, "astore_0\n");
|
|
|
|
break;
|
|
|
|
case astore_1:
|
|
|
|
fprintf(stderr, "astore_1\n");
|
|
|
|
break;
|
|
|
|
case astore_2:
|
|
|
|
fprintf(stderr, "astore_2\n");
|
|
|
|
break;
|
|
|
|
case astore_3:
|
|
|
|
fprintf(stderr, "astore_3\n");
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case athrow:
|
|
|
|
fprintf(stderr, "athrow\n");
|
|
|
|
break;
|
|
|
|
case baload:
|
|
|
|
fprintf(stderr, "baload\n");
|
|
|
|
break;
|
|
|
|
case bastore:
|
|
|
|
fprintf(stderr, "bastore\n");
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case bipush:
|
|
|
|
fprintf(stderr, "bipush %02x\n", code[ip++]);
|
|
|
|
break;
|
|
|
|
case caload:
|
|
|
|
fprintf(stderr, "caload\n");
|
|
|
|
break;
|
|
|
|
case castore:
|
|
|
|
fprintf(stderr, "castore\n");
|
|
|
|
break;
|
|
|
|
case checkcast:
|
|
|
|
fprintf(stderr, "checkcast %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case d2f:
|
|
|
|
fprintf(stderr, "d2f\n");
|
|
|
|
break;
|
|
|
|
case d2i:
|
|
|
|
fprintf(stderr, "d2i\n");
|
|
|
|
break;
|
|
|
|
case d2l:
|
|
|
|
fprintf(stderr, "d2l\n");
|
|
|
|
break;
|
|
|
|
case dadd:
|
|
|
|
fprintf(stderr, "dadd\n");
|
|
|
|
break;
|
|
|
|
case daload:
|
|
|
|
fprintf(stderr, "daload\n");
|
|
|
|
break;
|
|
|
|
case dastore:
|
|
|
|
fprintf(stderr, "dastore\n");
|
|
|
|
break;
|
|
|
|
case dcmpg:
|
|
|
|
fprintf(stderr, "dcmpg\n");
|
|
|
|
break;
|
|
|
|
case dcmpl:
|
|
|
|
fprintf(stderr, "dcmpl\n");
|
|
|
|
break;
|
|
|
|
case dconst_0:
|
|
|
|
fprintf(stderr, "dconst_0\n");
|
|
|
|
break;
|
|
|
|
case dconst_1:
|
|
|
|
fprintf(stderr, "dconst_1\n");
|
|
|
|
break;
|
|
|
|
case ddiv:
|
|
|
|
fprintf(stderr, "ddiv\n");
|
|
|
|
break;
|
|
|
|
case dmul:
|
|
|
|
fprintf(stderr, "dmul\n");
|
|
|
|
break;
|
|
|
|
case dneg:
|
|
|
|
fprintf(stderr, "dneg\n");
|
|
|
|
break;
|
|
|
|
case vm::drem:
|
|
|
|
fprintf(stderr, "drem\n");
|
|
|
|
break;
|
|
|
|
case dsub:
|
|
|
|
fprintf(stderr, "dsub\n");
|
|
|
|
break;
|
|
|
|
case vm::dup:
|
|
|
|
fprintf(stderr, "dup\n");
|
|
|
|
break;
|
|
|
|
case dup_x1:
|
|
|
|
fprintf(stderr, "dup_x1\n");
|
|
|
|
break;
|
|
|
|
case dup_x2:
|
|
|
|
fprintf(stderr, "dup_x2\n");
|
|
|
|
break;
|
|
|
|
case vm::dup2:
|
|
|
|
fprintf(stderr, "dup2\n");
|
|
|
|
break;
|
|
|
|
case dup2_x1:
|
|
|
|
fprintf(stderr, "dup2_x1\n");
|
|
|
|
break;
|
|
|
|
case dup2_x2:
|
|
|
|
fprintf(stderr, "dup2_x2\n");
|
|
|
|
break;
|
|
|
|
case f2d:
|
|
|
|
fprintf(stderr, "f2d\n");
|
|
|
|
break;
|
|
|
|
case f2i:
|
|
|
|
fprintf(stderr, "f2i\n");
|
|
|
|
break;
|
|
|
|
case f2l:
|
|
|
|
fprintf(stderr, "f2l\n");
|
|
|
|
break;
|
|
|
|
case fadd:
|
|
|
|
fprintf(stderr, "fadd\n");
|
|
|
|
break;
|
|
|
|
case faload:
|
|
|
|
fprintf(stderr, "faload\n");
|
|
|
|
break;
|
|
|
|
case fastore:
|
|
|
|
fprintf(stderr, "fastore\n");
|
|
|
|
break;
|
|
|
|
case fcmpg:
|
|
|
|
fprintf(stderr, "fcmpg\n");
|
|
|
|
break;
|
|
|
|
case fcmpl:
|
|
|
|
fprintf(stderr, "fcmpl\n");
|
|
|
|
break;
|
|
|
|
case fconst_0:
|
|
|
|
fprintf(stderr, "fconst_0\n");
|
|
|
|
break;
|
|
|
|
case fconst_1:
|
|
|
|
fprintf(stderr, "fconst_1\n");
|
|
|
|
break;
|
|
|
|
case fconst_2:
|
|
|
|
fprintf(stderr, "fconst_2\n");
|
|
|
|
break;
|
|
|
|
case fdiv:
|
|
|
|
fprintf(stderr, "fdiv\n");
|
|
|
|
break;
|
|
|
|
case fmul:
|
|
|
|
fprintf(stderr, "fmul\n");
|
|
|
|
break;
|
|
|
|
case fneg:
|
|
|
|
fprintf(stderr, "fneg\n");
|
|
|
|
break;
|
|
|
|
case frem:
|
|
|
|
fprintf(stderr, "frem\n");
|
|
|
|
break;
|
|
|
|
case fsub:
|
|
|
|
fprintf(stderr, "fsub\n");
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case getfield:
|
|
|
|
fprintf(stderr, "getfield %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case getstatic:
|
|
|
|
fprintf(stderr, "getstatic %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case goto_: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "goto %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
|
|
|
case goto_w: {
|
|
|
|
int32_t offset = read32(code, ip);
|
|
|
|
fprintf(stderr, "goto_w %08x\n", offset + ip - 5);
|
|
|
|
} break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case i2b:
|
|
|
|
fprintf(stderr, "i2b\n");
|
|
|
|
break;
|
|
|
|
case i2c:
|
|
|
|
fprintf(stderr, "i2c\n");
|
|
|
|
break;
|
|
|
|
case i2d:
|
|
|
|
fprintf(stderr, "i2d\n");
|
|
|
|
break;
|
|
|
|
case i2f:
|
|
|
|
fprintf(stderr, "i2f\n");
|
|
|
|
break;
|
|
|
|
case i2l:
|
|
|
|
fprintf(stderr, "i2l\n");
|
|
|
|
break;
|
|
|
|
case i2s:
|
|
|
|
fprintf(stderr, "i2s\n");
|
|
|
|
break;
|
|
|
|
case iadd:
|
|
|
|
fprintf(stderr, "iadd\n");
|
|
|
|
break;
|
|
|
|
case iaload:
|
|
|
|
fprintf(stderr, "iaload\n");
|
|
|
|
break;
|
|
|
|
case iand:
|
|
|
|
fprintf(stderr, "iand\n");
|
|
|
|
break;
|
|
|
|
case iastore:
|
|
|
|
fprintf(stderr, "iastore\n");
|
|
|
|
break;
|
|
|
|
case iconst_m1:
|
|
|
|
fprintf(stderr, "iconst_m1\n");
|
|
|
|
break;
|
|
|
|
case iconst_0:
|
|
|
|
fprintf(stderr, "iconst_0\n");
|
|
|
|
break;
|
|
|
|
case iconst_1:
|
|
|
|
fprintf(stderr, "iconst_1\n");
|
|
|
|
break;
|
|
|
|
case iconst_2:
|
|
|
|
fprintf(stderr, "iconst_2\n");
|
|
|
|
break;
|
|
|
|
case iconst_3:
|
|
|
|
fprintf(stderr, "iconst_3\n");
|
|
|
|
break;
|
|
|
|
case iconst_4:
|
|
|
|
fprintf(stderr, "iconst_4\n");
|
|
|
|
break;
|
|
|
|
case iconst_5:
|
|
|
|
fprintf(stderr, "iconst_5\n");
|
|
|
|
break;
|
|
|
|
case idiv:
|
|
|
|
fprintf(stderr, "idiv\n");
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case if_acmpeq: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "if_acmpeq %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
|
|
|
case if_acmpne: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "if_acmpne %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
|
|
|
case if_icmpeq: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "if_icmpeq %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
|
|
|
case if_icmpne: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "if_icmpne %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case if_icmpgt: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "if_icmpgt %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
|
|
|
case if_icmpge: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "if_icmpge %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
|
|
|
case if_icmplt: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "if_icmplt %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
|
|
|
case if_icmple: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "if_icmple %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case ifeq: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "ifeq %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
|
|
|
case ifne: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "ifne %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
|
|
|
case ifgt: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "ifgt %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
|
|
|
case ifge: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "ifge %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
|
|
|
case iflt: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "iflt %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
|
|
|
case ifle: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "ifle %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case ifnonnull: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "ifnonnull %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
|
|
|
case ifnull: {
|
|
|
|
int16_t offset = read16(code, ip);
|
|
|
|
fprintf(stderr, "ifnull %04x\n", offset + ip - 3);
|
|
|
|
} break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case iinc: {
|
|
|
|
uint8_t a = code[ip++];
|
|
|
|
uint8_t b = code[ip++];
|
|
|
|
fprintf(stderr, "iinc %02x %02x\n", a, b);
|
|
|
|
} break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case iload:
|
|
|
|
fprintf(stderr, "iload %02x\n", code[ip++]);
|
|
|
|
break;
|
|
|
|
case fload:
|
|
|
|
fprintf(stderr, "fload %02x\n", code[ip++]);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case iload_0:
|
|
|
|
fprintf(stderr, "iload_0\n");
|
|
|
|
break;
|
|
|
|
case fload_0:
|
|
|
|
fprintf(stderr, "fload_0\n");
|
|
|
|
break;
|
|
|
|
case iload_1:
|
|
|
|
fprintf(stderr, "iload_1\n");
|
|
|
|
break;
|
|
|
|
case fload_1:
|
|
|
|
fprintf(stderr, "fload_1\n");
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case iload_2:
|
|
|
|
fprintf(stderr, "iload_2\n");
|
|
|
|
break;
|
|
|
|
case fload_2:
|
|
|
|
fprintf(stderr, "fload_2\n");
|
|
|
|
break;
|
|
|
|
case iload_3:
|
|
|
|
fprintf(stderr, "iload_3\n");
|
|
|
|
break;
|
|
|
|
case fload_3:
|
|
|
|
fprintf(stderr, "fload_3\n");
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case imul:
|
|
|
|
fprintf(stderr, "imul\n");
|
|
|
|
break;
|
|
|
|
case ineg:
|
|
|
|
fprintf(stderr, "ineg\n");
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case instanceof:
|
|
|
|
fprintf(stderr, "instanceof %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case invokeinterface:
|
|
|
|
fprintf(stderr, "invokeinterface %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case invokespecial:
|
|
|
|
fprintf(stderr, "invokespecial %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case invokestatic:
|
|
|
|
fprintf(stderr, "invokestatic %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case invokevirtual:
|
|
|
|
fprintf(stderr, "invokevirtual %04x\n", read16(code, ip));
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case ior:
|
|
|
|
fprintf(stderr, "ior\n");
|
|
|
|
break;
|
|
|
|
case irem:
|
|
|
|
fprintf(stderr, "irem\n");
|
|
|
|
break;
|
|
|
|
case ireturn:
|
|
|
|
fprintf(stderr, "ireturn\n");
|
|
|
|
break;
|
|
|
|
case freturn:
|
|
|
|
fprintf(stderr, "freturn\n");
|
|
|
|
break;
|
|
|
|
case ishl:
|
|
|
|
fprintf(stderr, "ishl\n");
|
|
|
|
break;
|
|
|
|
case ishr:
|
|
|
|
fprintf(stderr, "ishr\n");
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case istore:
|
|
|
|
fprintf(stderr, "istore %02x\n", code[ip++]);
|
|
|
|
break;
|
|
|
|
case fstore:
|
|
|
|
fprintf(stderr, "fstore %02x\n", code[ip++]);
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case istore_0:
|
|
|
|
fprintf(stderr, "istore_0\n");
|
|
|
|
break;
|
|
|
|
case fstore_0:
|
|
|
|
fprintf(stderr, "fstore_0\n");
|
|
|
|
break;
|
|
|
|
case istore_1:
|
|
|
|
fprintf(stderr, "istore_1\n");
|
|
|
|
break;
|
|
|
|
case fstore_1:
|
|
|
|
fprintf(stderr, "fstore_1\n");
|
|
|
|
break;
|
|
|
|
case istore_2:
|
|
|
|
fprintf(stderr, "istore_2\n");
|
|
|
|
break;
|
|
|
|
case fstore_2:
|
|
|
|
fprintf(stderr, "fstore_2\n");
|
|
|
|
break;
|
|
|
|
case istore_3:
|
|
|
|
fprintf(stderr, "istore_3\n");
|
|
|
|
break;
|
|
|
|
case fstore_3:
|
|
|
|
fprintf(stderr, "fstore_3\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case isub:
|
|
|
|
fprintf(stderr, "isub\n");
|
|
|
|
break;
|
|
|
|
case iushr:
|
|
|
|
fprintf(stderr, "iushr\n");
|
|
|
|
break;
|
|
|
|
case ixor:
|
|
|
|
fprintf(stderr, "ixor\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case jsr:
|
|
|
|
fprintf(stderr, "jsr %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case jsr_w:
|
|
|
|
fprintf(stderr, "jsr_w %08x\n", read32(code, ip));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case l2d:
|
|
|
|
fprintf(stderr, "l2d\n");
|
|
|
|
break;
|
|
|
|
case l2f:
|
|
|
|
fprintf(stderr, "l2f\n");
|
|
|
|
break;
|
|
|
|
case l2i:
|
|
|
|
fprintf(stderr, "l2i\n");
|
|
|
|
break;
|
|
|
|
case ladd:
|
|
|
|
fprintf(stderr, "ladd\n");
|
|
|
|
break;
|
|
|
|
case laload:
|
|
|
|
fprintf(stderr, "laload\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case land:
|
|
|
|
fprintf(stderr, "land\n");
|
|
|
|
break;
|
|
|
|
case lastore:
|
|
|
|
fprintf(stderr, "lastore\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lcmp:
|
|
|
|
fprintf(stderr, "lcmp\n");
|
|
|
|
break;
|
|
|
|
case lconst_0:
|
|
|
|
fprintf(stderr, "lconst_0\n");
|
|
|
|
break;
|
|
|
|
case lconst_1:
|
|
|
|
fprintf(stderr, "lconst_1\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ldc:
|
|
|
|
fprintf(stderr, "ldc %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case ldc_w:
|
|
|
|
fprintf(stderr, "ldc_w %08x\n", read32(code, ip));
|
|
|
|
break;
|
|
|
|
case ldc2_w:
|
|
|
|
fprintf(stderr, "ldc2_w %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ldiv_:
|
|
|
|
fprintf(stderr, "ldiv_\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lload:
|
|
|
|
fprintf(stderr, "lload %02x\n", code[ip++]);
|
|
|
|
break;
|
|
|
|
case dload:
|
|
|
|
fprintf(stderr, "dload %02x\n", code[ip++]);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lload_0:
|
|
|
|
fprintf(stderr, "lload_0\n");
|
|
|
|
break;
|
|
|
|
case dload_0:
|
|
|
|
fprintf(stderr, "dload_0\n");
|
|
|
|
break;
|
|
|
|
case lload_1:
|
|
|
|
fprintf(stderr, "lload_1\n");
|
|
|
|
break;
|
|
|
|
case dload_1:
|
|
|
|
fprintf(stderr, "dload_1\n");
|
|
|
|
break;
|
|
|
|
case lload_2:
|
|
|
|
fprintf(stderr, "lload_2\n");
|
|
|
|
break;
|
|
|
|
case dload_2:
|
|
|
|
fprintf(stderr, "dload_2\n");
|
|
|
|
break;
|
|
|
|
case lload_3:
|
|
|
|
fprintf(stderr, "lload_3\n");
|
|
|
|
break;
|
|
|
|
case dload_3:
|
|
|
|
fprintf(stderr, "dload_3\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lmul:
|
|
|
|
fprintf(stderr, "lmul\n");
|
|
|
|
break;
|
|
|
|
case lneg:
|
|
|
|
fprintf(stderr, "lneg\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lookupswitch: {
|
|
|
|
int32_t default_ = read32(code, ip);
|
|
|
|
int32_t pairCount = read32(code, ip);
|
|
|
|
fprintf(stderr,
|
|
|
|
"lookupswitch default: %d pairCount: %d\n",
|
|
|
|
default_,
|
|
|
|
pairCount);
|
|
|
|
|
|
|
|
for (int i = 0; i < pairCount; i++) {
|
|
|
|
int32_t k = read32(code, ip);
|
|
|
|
int32_t d = read32(code, ip);
|
|
|
|
fprintf(stderr, "%s key: %02x dest: %2x\n", prefix, k, d);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case lor:
|
|
|
|
fprintf(stderr, "lor\n");
|
|
|
|
break;
|
|
|
|
case lrem:
|
|
|
|
fprintf(stderr, "lrem\n");
|
|
|
|
break;
|
|
|
|
case lreturn:
|
|
|
|
fprintf(stderr, "lreturn\n");
|
|
|
|
break;
|
|
|
|
case dreturn:
|
|
|
|
fprintf(stderr, "dreturn\n");
|
|
|
|
break;
|
|
|
|
case lshl:
|
|
|
|
fprintf(stderr, "lshl\n");
|
|
|
|
break;
|
|
|
|
case lshr:
|
|
|
|
fprintf(stderr, "lshr\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lstore:
|
|
|
|
fprintf(stderr, "lstore %02x\n", code[ip++]);
|
|
|
|
break;
|
|
|
|
case dstore:
|
|
|
|
fprintf(stderr, "dstore %02x\n", code[ip++]);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lstore_0:
|
|
|
|
fprintf(stderr, "lstore_0\n");
|
|
|
|
break;
|
|
|
|
case dstore_0:
|
|
|
|
fprintf(stderr, "dstore_0\n");
|
|
|
|
break;
|
|
|
|
case lstore_1:
|
|
|
|
fprintf(stderr, "lstore_1\n");
|
|
|
|
break;
|
|
|
|
case dstore_1:
|
|
|
|
fprintf(stderr, "dstore_1\n");
|
|
|
|
break;
|
|
|
|
case lstore_2:
|
|
|
|
fprintf(stderr, "lstore_2\n");
|
|
|
|
break;
|
|
|
|
case dstore_2:
|
|
|
|
fprintf(stderr, "dstore_2\n");
|
|
|
|
break;
|
|
|
|
case lstore_3:
|
|
|
|
fprintf(stderr, "lstore_3\n");
|
|
|
|
break;
|
|
|
|
case dstore_3:
|
|
|
|
fprintf(stderr, "dstore_3\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case lsub:
|
|
|
|
fprintf(stderr, "lsub\n");
|
|
|
|
break;
|
|
|
|
case lushr:
|
|
|
|
fprintf(stderr, "lushr\n");
|
|
|
|
break;
|
|
|
|
case lxor:
|
|
|
|
fprintf(stderr, "lxor\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case monitorenter:
|
|
|
|
fprintf(stderr, "monitorenter\n");
|
|
|
|
break;
|
|
|
|
case monitorexit:
|
|
|
|
fprintf(stderr, "monitorexit\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case multianewarray: {
|
|
|
|
unsigned type = read16(code, ip);
|
|
|
|
fprintf(stderr, "multianewarray %04x %02x\n", type, code[ip++]);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case new_:
|
|
|
|
fprintf(stderr, "new %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case newarray:
|
|
|
|
fprintf(stderr, "newarray %02x\n", code[ip++]);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case nop:
|
|
|
|
fprintf(stderr, "nop\n");
|
|
|
|
break;
|
|
|
|
case pop_:
|
|
|
|
fprintf(stderr, "pop\n");
|
|
|
|
break;
|
|
|
|
case pop2:
|
|
|
|
fprintf(stderr, "pop2\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case putfield:
|
|
|
|
fprintf(stderr, "putfield %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case putstatic:
|
|
|
|
fprintf(stderr, "putstatic %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ret:
|
|
|
|
fprintf(stderr, "ret %02x\n", code[ip++]);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case return_:
|
|
|
|
fprintf(stderr, "return_\n");
|
|
|
|
break;
|
|
|
|
case saload:
|
|
|
|
fprintf(stderr, "saload\n");
|
|
|
|
break;
|
|
|
|
case sastore:
|
|
|
|
fprintf(stderr, "sastore\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case sipush:
|
|
|
|
fprintf(stderr, "sipush %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case swap:
|
|
|
|
fprintf(stderr, "swap\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case tableswitch: {
|
|
|
|
int32_t default_ = read32(code, ip);
|
|
|
|
int32_t bottom = read32(code, ip);
|
|
|
|
int32_t top = read32(code, ip);
|
|
|
|
fprintf(stderr,
|
|
|
|
"tableswitch default: %d bottom: %d top: %d\n",
|
|
|
|
default_,
|
|
|
|
bottom,
|
|
|
|
top);
|
|
|
|
|
|
|
|
for (int i = 0; i < top - bottom + 1; i++) {
|
|
|
|
int32_t d = read32(code, ip);
|
|
|
|
fprintf(stderr, "%s key: %d dest: %2x\n", prefix, i + bottom, d);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case wide: {
|
|
|
|
switch (code[ip++]) {
|
|
|
|
case aload:
|
|
|
|
fprintf(stderr, "wide aload %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case astore:
|
|
|
|
fprintf(stderr, "wide astore %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case iinc:
|
|
|
|
fprintf(stderr,
|
|
|
|
"wide iinc %04x %04x\n",
|
|
|
|
read16(code, ip),
|
|
|
|
read16(code, ip));
|
|
|
|
break;
|
|
|
|
case iload:
|
|
|
|
fprintf(stderr, "wide iload %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case istore:
|
|
|
|
fprintf(stderr, "wide istore %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case lload:
|
|
|
|
fprintf(stderr, "wide lload %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case lstore:
|
|
|
|
fprintf(stderr, "wide lstore %04x\n", read16(code, ip));
|
|
|
|
break;
|
|
|
|
case ret:
|
|
|
|
fprintf(stderr, "wide ret %04x\n", read16(code, ip));
|
|
|
|
break;
|
2012-05-22 19:53:32 +00:00
|
|
|
|
|
|
|
default: {
|
2014-07-11 15:50:18 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
"unknown wide instruction %02x %04x\n",
|
|
|
|
instr,
|
|
|
|
read16(code, ip));
|
|
|
|
}
|
2012-05-22 19:53:32 +00:00
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
default: {
|
|
|
|
fprintf(stderr, "unknown instruction %02x\n", instr);
|
|
|
|
}
|
2012-05-22 19:53:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcCode* parseCode(Thread* t, Stream& s, GcSingleton* pool)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
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();
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (DebugClassReader) {
|
|
|
|
fprintf(stderr,
|
|
|
|
" code: maxStack %d maxLocals %d length %d\n",
|
|
|
|
maxStack,
|
|
|
|
maxLocals,
|
|
|
|
length);
|
2012-05-22 19:53:32 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcCode* code = makeCode(t, pool, 0, 0, 0, 0, 0, maxStack, maxLocals, length);
|
|
|
|
s.read(code->body().begin(), length);
|
2007-07-16 23:58:37 +00:00
|
|
|
PROTECT(t, code);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (DebugClassReader) {
|
2014-06-29 05:48:17 +00:00
|
|
|
disassembleCode(" ", code->body().begin(), length);
|
2012-05-22 19:53:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned ehtLength = s.read2();
|
|
|
|
if (ehtLength) {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcExceptionHandlerTable* 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();
|
2014-07-11 15:47:57 +00:00
|
|
|
eht->body()[i] = exceptionHandler(start, end, ip, catchType);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
code->setExceptionHandlerTable(t, eht);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned attributeCount = s.read2();
|
|
|
|
for (unsigned j = 0; j < attributeCount; ++j) {
|
2014-07-11 15:47:57 +00:00
|
|
|
GcByteArray* name
|
|
|
|
= cast<GcByteArray>(t, 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"),
|
2014-07-11 15:47:57 +00:00
|
|
|
name->body().begin()) == 0) {
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned lntLength = s.read2();
|
2014-06-29 05:48:17 +00:00
|
|
|
GcLineNumberTable* 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();
|
2014-06-29 05:48:17 +00:00
|
|
|
lnt->body()[i] = lineNumber(ip, line);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
code->setLineNumberTable(t, lnt);
|
2007-07-14 17:31:01 +00:00
|
|
|
} else {
|
|
|
|
s.skip(length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return code;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcList* addInterfaceMethods(Thread* t,
|
|
|
|
GcClass* class_,
|
|
|
|
GcHashMap* virtualMap,
|
|
|
|
unsigned* virtualCount,
|
|
|
|
bool makeList)
|
2009-08-10 13:56:16 +00:00
|
|
|
{
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* itable = cast<GcArray>(t, class_->interfaceTable());
|
2009-08-10 13:56:16 +00:00
|
|
|
if (itable) {
|
|
|
|
PROTECT(t, class_);
|
2014-06-29 05:48:17 +00:00
|
|
|
PROTECT(t, virtualMap);
|
2009-08-10 13:56:16 +00:00
|
|
|
PROTECT(t, itable);
|
2014-06-29 05:48:17 +00:00
|
|
|
|
|
|
|
GcList* list = 0;
|
2009-08-10 13:56:16 +00:00
|
|
|
PROTECT(t, list);
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcMethod* method = 0;
|
2009-08-10 13:56:16 +00:00
|
|
|
PROTECT(t, method);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* vtable = 0;
|
2009-08-10 13:56:16 +00:00
|
|
|
PROTECT(t, vtable);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
unsigned stride = (class_->flags() & ACC_INTERFACE) ? 1 : 2;
|
|
|
|
for (unsigned i = 0; i < itable->length(); i += stride) {
|
2014-07-11 15:47:57 +00:00
|
|
|
vtable = cast<GcArray>(
|
|
|
|
t, cast<GcClass>(t, itable->body()[i])->virtualTable());
|
2009-08-10 13:56:16 +00:00
|
|
|
if (vtable) {
|
2014-06-29 05:48:17 +00:00
|
|
|
for (unsigned j = 0; j < vtable->length(); ++j) {
|
|
|
|
method = cast<GcMethod>(t, vtable->body()[j]);
|
2014-07-11 15:47:57 +00:00
|
|
|
GcTriple* n
|
|
|
|
= hashMapFindNode(t, virtualMap, method, methodHash, methodEqual);
|
2009-08-10 13:56:16 +00:00
|
|
|
if (n == 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
method = makeMethod(t,
|
|
|
|
method->vmFlags(),
|
|
|
|
method->returnCode(),
|
|
|
|
method->parameterCount(),
|
|
|
|
method->parameterFootprint(),
|
|
|
|
method->flags(),
|
|
|
|
(*virtualCount)++,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
method->name(),
|
|
|
|
method->spec(),
|
|
|
|
0,
|
|
|
|
class_,
|
2016-05-14 18:16:18 +00:00
|
|
|
method->code());
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
hashMapInsert(t, virtualMap, method, method, methodHash);
|
2009-08-10 13:56:16 +00:00
|
|
|
|
|
|
|
if (makeList) {
|
|
|
|
if (list == 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
list = vm::makeList(t, 0, 0, 0);
|
2009-08-10 13:56:16 +00:00
|
|
|
}
|
2014-07-02 21:11:27 +00:00
|
|
|
listAppend(t, list, method);
|
2009-08-10 13:56:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void parseMethodTable(Thread* t, Stream& s, GcClass* class_, GcSingleton* pool)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, class_);
|
|
|
|
PROTECT(t, pool);
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcHashMap* virtualMap = makeHashMap(t, 0, 0);
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, virtualMap);
|
|
|
|
|
|
|
|
unsigned virtualCount = 0;
|
|
|
|
unsigned declaredVirtualCount = 0;
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* superVirtualTable = 0;
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, superVirtualTable);
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if ((class_->flags() & ACC_INTERFACE) == 0) {
|
|
|
|
if (class_->super()) {
|
2014-06-29 05:48:17 +00:00
|
|
|
superVirtualTable = cast<GcArray>(t, class_->super()->virtualTable());
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (superVirtualTable) {
|
2014-06-29 05:48:17 +00:00
|
|
|
virtualCount = superVirtualTable->length();
|
2007-07-14 17:31:01 +00:00
|
|
|
for (unsigned i = 0; i < virtualCount; ++i) {
|
2014-06-29 05:48:17 +00:00
|
|
|
object method = superVirtualTable->body()[i];
|
2007-07-14 17:31:01 +00:00
|
|
|
hashMapInsert(t, virtualMap, method, method, methodHash);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcList* newVirtuals = makeList(t, 0, 0, 0);
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, newVirtuals);
|
2014-07-11 15:50:18 +00:00
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
unsigned count = s.read2();
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (DebugClassReader) {
|
2012-05-22 19:53:32 +00:00
|
|
|
fprintf(stderr, " method count %d\n", count);
|
|
|
|
}
|
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
if (count) {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* methodTable = makeArray(t, count);
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, methodTable);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcMethodAddendum* addendum = 0;
|
2009-09-19 00:01:54 +00:00
|
|
|
PROTECT(t, addendum);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcCode* code = 0;
|
2009-09-19 00:01:54 +00:00
|
|
|
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();
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (DebugClassReader) {
|
2014-07-11 15:47:57 +00:00
|
|
|
fprintf(stderr,
|
|
|
|
" method flags %d name %d spec %d '%s%s'\n",
|
|
|
|
flags,
|
|
|
|
name,
|
|
|
|
spec,
|
|
|
|
cast<GcByteArray>(t, singletonObject(t, pool, name - 1))
|
|
|
|
->body()
|
|
|
|
.begin(),
|
|
|
|
cast<GcByteArray>(t, singletonObject(t, pool, spec - 1))
|
|
|
|
->body()
|
|
|
|
.begin());
|
2012-05-22 19:53:32 +00:00
|
|
|
}
|
|
|
|
|
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) {
|
2014-07-11 15:47:57 +00:00
|
|
|
GcByteArray* attributeName
|
|
|
|
= cast<GcByteArray>(t, 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"),
|
2014-07-11 15:47:57 +00:00
|
|
|
attributeName->body().begin()) == 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"),
|
2014-07-11 15:47:57 +00:00
|
|
|
attributeName->body().begin()) == 0) {
|
2010-09-10 21:05:29 +00:00
|
|
|
if (addendum == 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0, 0);
|
2010-09-10 21:05:29 +00:00
|
|
|
}
|
|
|
|
unsigned exceptionCount = s.read2();
|
2014-06-29 05:48:17 +00:00
|
|
|
GcShortArray* body = makeShortArray(t, exceptionCount);
|
2010-09-10 21:05:29 +00:00
|
|
|
for (unsigned i = 0; i < exceptionCount; ++i) {
|
2014-06-29 05:48:17 +00:00
|
|
|
body->body()[i] = s.read2();
|
2010-09-10 21:05:29 +00:00
|
|
|
}
|
2014-07-02 21:11:27 +00:00
|
|
|
addendum->setExceptionTable(t, body);
|
2014-07-11 15:47:57 +00:00
|
|
|
} else if (vm::strcmp(
|
|
|
|
reinterpret_cast<const int8_t*>("AnnotationDefault"),
|
|
|
|
attributeName->body().begin()) == 0) {
|
2011-03-18 03:42:15 +00:00
|
|
|
if (addendum == 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0, 0);
|
2011-03-18 03:42:15 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* body = makeByteArray(t, length);
|
2014-07-11 15:47:57 +00:00
|
|
|
s.read(reinterpret_cast<uint8_t*>(body->body().begin()), length);
|
2011-03-18 03:42:15 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
addendum->setAnnotationDefault(t, body);
|
2011-03-18 03:42:15 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("Signature"),
|
2014-07-11 15:47:57 +00:00
|
|
|
attributeName->body().begin()) == 0) {
|
2011-03-18 03:42:15 +00:00
|
|
|
if (addendum == 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0, 0);
|
2011-03-18 03:42:15 +00:00
|
|
|
}
|
2014-06-29 05:48:17 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
addendum->setSignature(t, singletonObject(t, pool, s.read2() - 1));
|
2014-07-11 15:47:57 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>(
|
|
|
|
"RuntimeVisibleAnnotations"),
|
|
|
|
attributeName->body().begin()) == 0) {
|
2010-09-10 21:05:29 +00:00
|
|
|
if (addendum == 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0, 0);
|
2010-09-10 21:05:29 +00:00
|
|
|
}
|
2011-03-18 03:42:15 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* body = makeByteArray(t, length);
|
2014-07-11 15:47:57 +00:00
|
|
|
s.read(reinterpret_cast<uint8_t*>(body->body().begin()), length);
|
2011-03-18 03:42:15 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
addendum->setAnnotationTable(t, body);
|
2014-07-11 15:47:57 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>(
|
|
|
|
"RuntimeVisibleParameterAnnotations"),
|
|
|
|
attributeName->body().begin()) == 0) {
|
2013-05-01 04:55:59 +00:00
|
|
|
if (addendum == 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
addendum = makeMethodAddendum(t, pool, 0, 0, 0, 0, 0);
|
2013-05-01 04:55:59 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* body = makeByteArray(t, length);
|
2014-07-11 15:47:57 +00:00
|
|
|
s.read(reinterpret_cast<uint8_t*>(body->body().begin()), length);
|
2013-05-01 04:55:59 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
addendum->setParameterAnnotationTable(t, body);
|
2007-07-14 17:31:01 +00:00
|
|
|
} else {
|
|
|
|
s.skip(length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
const char* specString = reinterpret_cast<const char*>(
|
|
|
|
cast<GcByteArray>(t, singletonObject(t, pool, spec - 1))
|
|
|
|
->body()
|
|
|
|
.begin());
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-09-26 23:23:03 +00:00
|
|
|
unsigned parameterCount;
|
2014-04-23 21:22:10 +00:00
|
|
|
unsigned parameterFootprint;
|
2007-09-26 23:23:03 +00:00
|
|
|
unsigned returnCode;
|
2014-07-11 15:50:18 +00:00
|
|
|
scanMethodSpec(t,
|
|
|
|
specString,
|
|
|
|
flags & ACC_STATIC,
|
|
|
|
¶meterCount,
|
|
|
|
¶meterFootprint,
|
|
|
|
&returnCode);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcMethod* method = t->m->processor->makeMethod(
|
|
|
|
t,
|
|
|
|
0, // vm flags
|
|
|
|
returnCode,
|
|
|
|
parameterCount,
|
|
|
|
parameterFootprint,
|
|
|
|
flags,
|
|
|
|
0, // offset
|
|
|
|
cast<GcByteArray>(t, singletonObject(t, pool, name - 1)),
|
|
|
|
cast<GcByteArray>(t, singletonObject(t, pool, spec - 1)),
|
|
|
|
addendum,
|
|
|
|
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)) {
|
2014-07-11 15:50:18 +00:00
|
|
|
++declaredVirtualCount;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcTriple* p
|
|
|
|
= hashMapFindNode(t, virtualMap, method, methodHash, methodEqual);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
|
|
|
if (p) {
|
2014-06-29 05:48:17 +00:00
|
|
|
method->offset() = cast<GcMethod>(t, p->first())->offset();
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
p->setSecond(t, method);
|
2007-07-14 17:31:01 +00:00
|
|
|
} else {
|
2014-05-29 04:17:25 +00:00
|
|
|
method->offset() = virtualCount++;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
listAppend(t, newVirtuals, method);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
hashMapInsert(t, virtualMap, method, method, methodHash);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
2009-07-22 00:57:55 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (UNLIKELY((class_->flags() & ACC_INTERFACE) == 0
|
2014-07-11 15:47:57 +00:00
|
|
|
and vm::strcmp(reinterpret_cast<const int8_t*>("finalize"),
|
|
|
|
method->name()->body().begin()) == 0
|
|
|
|
and vm::strcmp(reinterpret_cast<const int8_t*>("()V"),
|
|
|
|
method->spec()->body().begin()) == 0
|
|
|
|
and (not emptyMethod(t, method)))) {
|
2014-05-29 04:17:25 +00:00
|
|
|
class_->vmFlags() |= HasFinalizerFlag;
|
2009-07-22 00:57:55 +00:00
|
|
|
}
|
2007-11-05 14:28:46 +00:00
|
|
|
} else {
|
2014-05-29 04:17:25 +00:00
|
|
|
method->offset() = i;
|
2007-11-05 14:28:46 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
if (vm::strcmp(reinterpret_cast<const int8_t*>("<clinit>"),
|
|
|
|
method->name()->body().begin()) == 0) {
|
2014-05-29 04:17:25 +00:00
|
|
|
method->vmFlags() |= ClassInitFlag;
|
|
|
|
class_->vmFlags() |= NeedInitFlag;
|
2014-07-11 15:47:57 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("<init>"),
|
|
|
|
method->name()->body().begin()) == 0) {
|
2014-05-29 04:17:25 +00:00
|
|
|
method->vmFlags() |= ConstructorFlag;
|
2007-11-05 14:28:46 +00:00
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
methodTable->setBodyElement(t, i, method);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
class_->setMethodTable(t, methodTable);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcList* abstractVirtuals
|
|
|
|
= addInterfaceMethods(t, class_, virtualMap, &virtualCount, true);
|
2013-12-06 22:45:46 +00:00
|
|
|
|
2009-08-10 13:56:16 +00:00
|
|
|
PROTECT(t, abstractVirtuals);
|
|
|
|
|
2008-01-28 15:12:06 +00:00
|
|
|
bool populateInterfaceVtables = false;
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
if (declaredVirtualCount == 0 and abstractVirtuals == 0
|
|
|
|
and (class_->flags() & ACC_INTERFACE) == 0) {
|
2014-05-29 04:17:25 +00:00
|
|
|
if (class_->super()) {
|
2008-01-21 23:42:12 +00:00
|
|
|
// inherit virtual table from superclass
|
2014-07-02 21:11:27 +00:00
|
|
|
class_->setVirtualTable(t, superVirtualTable);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
2014-06-21 04:16:33 +00:00
|
|
|
if (class_->super()->interfaceTable()
|
2014-06-29 05:48:17 +00:00
|
|
|
and cast<GcArray>(t, class_->interfaceTable())->length()
|
2014-07-11 15:47:57 +00:00
|
|
|
== cast<GcArray>(t, class_->super()->interfaceTable())
|
|
|
|
->length()) {
|
2008-01-21 23:42:12 +00:00
|
|
|
// inherit interface table from superclass
|
2014-06-26 01:42:16 +00:00
|
|
|
class_->setInterfaceTable(t, class_->super()->interfaceTable());
|
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.
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* vtable = makeArray(t, 0);
|
2014-07-02 21:11:27 +00:00
|
|
|
class_->setVirtualTable(t, vtable);
|
2007-11-27 22:23:00 +00:00
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
} else if (virtualCount) {
|
|
|
|
// generate class vtable
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* vtable = makeArray(t, virtualCount);
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2007-08-14 00:37:00 +00:00
|
|
|
unsigned i = 0;
|
2014-05-29 04:17:25 +00:00
|
|
|
if (class_->flags() & 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();) {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcMethod* method = cast<GcMethod>(t, it.next()->first());
|
|
|
|
assertT(t, vtable->body()[method->offset()] == 0);
|
2014-07-02 21:11:27 +00:00
|
|
|
vtable->setBodyElement(t, method->offset(), method);
|
2014-07-11 15:50:18 +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) {
|
2014-06-29 05:48:17 +00:00
|
|
|
for (; i < superVirtualTable->length(); ++i) {
|
|
|
|
object method = superVirtualTable->body()[i];
|
2007-07-14 17:31:01 +00:00
|
|
|
method = hashMapFind(t, virtualMap, method, methodHash, methodEqual);
|
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
vtable->setBodyElement(t, i, method);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
for (GcPair* p = cast<GcPair>(t, newVirtuals->front()); p;
|
|
|
|
p = cast<GcPair>(t, p->second())) {
|
2014-06-26 01:42:16 +00:00
|
|
|
vtable->setBodyElement(t, i, p->first());
|
2014-07-11 15:50:18 +00:00
|
|
|
++i;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
2013-12-06 22:45:46 +00:00
|
|
|
}
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2013-12-06 22:45:46 +00:00
|
|
|
if (abstractVirtuals) {
|
|
|
|
PROTECT(t, vtable);
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
object originalMethodTable = class_->methodTable();
|
fix Class.getDeclaredMethods
getDeclaredMethods was returning methods which were inherited from
interfaces but not (re)declared in the class itself, due to the VM's
internal use of VMClass.methodTable differing from its role in
reflection. For reflection, we must only include the declared
methods, not the inherited but un-redeclared ones.
Previously, we saved the original method table in
ClassAddendum.methodTable before creating a new one which contains
both declared and inherited methods. That wasted space, so this patch
replaces ClassAddendum.methodTable with
ClassAddendum.declaredMethodCount, which specifies how many of the
methods in VMClass.methodTable were declared in that class.
Alternatively, we could ensure that undeclared methods always have
their VMMethod.class_ field set to the declaring class instead of the
inheriting class. I tried this, but it led to subtle crashes in
interface method lookup. The rest of the VM relies not only on
VMClass.methodTable containing all inherited interface methods but
also that those methods point to the inheriting class, not the
declaring class. Changing those assumptions would be a much bigger
(and more dangerous in terms of regression potential) effort than I
care to take on right now. The solution I chose is a bit ugly, but
it's safe.
2014-03-03 16:56:26 +00:00
|
|
|
PROTECT(t, originalMethodTable);
|
2011-04-10 03:20:56 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
unsigned oldLength
|
|
|
|
= class_->methodTable()
|
|
|
|
? cast<GcArray>(t, class_->methodTable())->length()
|
|
|
|
: 0;
|
2012-01-13 23:51:39 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcClassAddendum* addendum = getClassAddendum(t, class_, pool);
|
|
|
|
addendum->declaredMethodCount() = oldLength;
|
fix Class.getDeclaredMethods
getDeclaredMethods was returning methods which were inherited from
interfaces but not (re)declared in the class itself, due to the VM's
internal use of VMClass.methodTable differing from its role in
reflection. For reflection, we must only include the declared
methods, not the inherited but un-redeclared ones.
Previously, we saved the original method table in
ClassAddendum.methodTable before creating a new one which contains
both declared and inherited methods. That wasted space, so this patch
replaces ClassAddendum.methodTable with
ClassAddendum.declaredMethodCount, which specifies how many of the
methods in VMClass.methodTable were declared in that class.
Alternatively, we could ensure that undeclared methods always have
their VMMethod.class_ field set to the declaring class instead of the
inheriting class. I tried this, but it led to subtle crashes in
interface method lookup. The rest of the VM relies not only on
VMClass.methodTable containing all inherited interface methods but
also that those methods point to the inheriting class, not the
declaring class. Changing those assumptions would be a much bigger
(and more dangerous in terms of regression potential) effort than I
care to take on right now. The solution I chose is a bit ugly, but
it's safe.
2014-03-03 16:56:26 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcArray* newMethodTable
|
|
|
|
= makeArray(t, oldLength + abstractVirtuals->size());
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2013-12-06 22:45:46 +00:00
|
|
|
if (oldLength) {
|
2014-06-26 01:42:16 +00:00
|
|
|
GcArray* mtable = cast<GcArray>(t, class_->methodTable());
|
2014-07-11 15:47:57 +00:00
|
|
|
for (size_t i = 0; i < oldLength; i++) {
|
2014-06-26 01:42:16 +00:00
|
|
|
newMethodTable->setBodyElement(t, i, mtable->body()[i]);
|
|
|
|
}
|
2013-12-06 22:45:46 +00:00
|
|
|
}
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
mark(t, newMethodTable, ArrayBody, oldLength);
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2013-12-06 22:45:46 +00:00
|
|
|
unsigned mti = oldLength;
|
2014-07-11 15:47:57 +00:00
|
|
|
for (GcPair* p = cast<GcPair>(t, abstractVirtuals->front()); p;
|
|
|
|
p = cast<GcPair>(t, p->second())) {
|
2014-06-26 01:42:16 +00:00
|
|
|
newMethodTable->setBodyElement(t, mti++, p->first());
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if ((class_->flags() & ACC_INTERFACE) == 0) {
|
2014-06-26 01:42:16 +00:00
|
|
|
vtable->setBodyElement(t, i++, p->first());
|
2009-08-10 13:56:16 +00:00
|
|
|
}
|
2013-12-06 22:45:46 +00:00
|
|
|
}
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
assertT(t, newMethodTable->length() == mti);
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
class_->setMethodTable(t, newMethodTable);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
assertT(t, vtable->length() == i);
|
2007-08-14 00:37:00 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
class_->setVirtualTable(t, 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
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* itable = cast<GcArray>(t, class_->interfaceTable());
|
2008-01-28 15:12:06 +00:00
|
|
|
if (itable) {
|
|
|
|
PROTECT(t, itable);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
for (unsigned i = 0; i < itable->length(); i += 2) {
|
2014-07-11 15:47:57 +00:00
|
|
|
GcArray* ivtable = cast<GcArray>(
|
|
|
|
t, cast<GcClass>(t, itable->body()[i])->virtualTable());
|
2008-01-28 15:12:06 +00:00
|
|
|
if (ivtable) {
|
2014-06-26 01:42:16 +00:00
|
|
|
GcArray* vtable = cast<GcArray>(t, itable->body()[i + 1]);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
for (unsigned j = 0; j < ivtable->length(); ++j) {
|
|
|
|
object method = ivtable->body()[j];
|
2014-07-11 15:50:18 +00:00
|
|
|
method
|
|
|
|
= hashMapFind(t, virtualMap, method, methodHash, methodEqual);
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, method);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
vtable->setBodyElement(t, j, method);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void parseAttributeTable(Thread* t,
|
|
|
|
Stream& s,
|
|
|
|
GcClass* class_,
|
|
|
|
GcSingleton* pool)
|
2009-08-27 22:26:25 +00:00
|
|
|
{
|
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) {
|
2014-07-11 15:47:57 +00:00
|
|
|
GcByteArray* name
|
|
|
|
= cast<GcByteArray>(t, singletonObject(t, pool, s.read2() - 1));
|
2009-08-27 22:26:25 +00:00
|
|
|
unsigned length = s.read4();
|
|
|
|
|
|
|
|
if (vm::strcmp(reinterpret_cast<const int8_t*>("SourceFile"),
|
2014-07-11 15:47:57 +00:00
|
|
|
name->body().begin()) == 0) {
|
|
|
|
class_->setSourceFile(
|
|
|
|
t, cast<GcByteArray>(t, singletonObject(t, pool, s.read2() - 1)));
|
2011-03-18 03:42:15 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("Signature"),
|
2014-07-11 15:47:57 +00:00
|
|
|
name->body().begin()) == 0) {
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClassAddendum* addendum = getClassAddendum(t, class_, pool);
|
2014-07-11 15:47:57 +00:00
|
|
|
addendum->setSignature(t, singletonObject(t, pool, s.read2() - 1));
|
2011-04-01 01:47:26 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("InnerClasses"),
|
2014-07-11 15:47:57 +00:00
|
|
|
name->body().begin()) == 0) {
|
2011-04-01 01:47:26 +00:00
|
|
|
unsigned innerClassCount = s.read2();
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* table = makeArray(t, innerClassCount);
|
2011-04-01 01:47:26 +00:00
|
|
|
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();
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcInnerClassReference* reference = makeInnerClassReference(
|
|
|
|
t,
|
|
|
|
inner
|
|
|
|
? cast<GcReference>(t, singletonObject(t, pool, inner - 1))
|
|
|
|
->name()
|
|
|
|
: 0,
|
|
|
|
outer
|
|
|
|
? cast<GcReference>(t, singletonObject(t, pool, outer - 1))
|
|
|
|
->name()
|
|
|
|
: 0,
|
|
|
|
name ? cast<GcByteArray>(t, singletonObject(t, pool, name - 1)) : 0,
|
|
|
|
flags);
|
2011-04-01 01:47:26 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
table->setBodyElement(t, i, reference);
|
2011-04-01 01:47:26 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClassAddendum* addendum = getClassAddendum(t, class_, pool);
|
2014-07-02 21:11:27 +00:00
|
|
|
addendum->setInnerClassTable(t, table);
|
2014-07-11 15:47:57 +00:00
|
|
|
} else if (vm::strcmp(
|
|
|
|
reinterpret_cast<const int8_t*>("RuntimeVisibleAnnotations"),
|
|
|
|
name->body().begin()) == 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* body = makeByteArray(t, length);
|
2011-04-10 03:20:56 +00:00
|
|
|
PROTECT(t, body);
|
2014-06-29 05:48:17 +00:00
|
|
|
s.read(reinterpret_cast<uint8_t*>(body->body().begin()), length);
|
2009-09-19 22:21:15 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClassAddendum* addendum = getClassAddendum(t, class_, pool);
|
2014-07-02 21:11:27 +00:00
|
|
|
addendum->setAnnotationTable(t, body);
|
2015-08-05 21:55:52 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("BootstrapMethods"),
|
|
|
|
name->body().begin()) == 0) {
|
|
|
|
unsigned count = s.read2();
|
|
|
|
GcArray* array = makeArray(t, count);
|
|
|
|
PROTECT(t, array);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
|
|
unsigned reference = s.read2() - 1;
|
|
|
|
unsigned argumentCount = s.read2();
|
|
|
|
GcCharArray* element = makeCharArray(t, 1 + argumentCount);
|
|
|
|
element->body()[0] = reference;
|
|
|
|
for (unsigned ai = 0; ai < argumentCount; ++ai) {
|
|
|
|
element->body()[1 + ai] = s.read2() - 1;
|
|
|
|
}
|
|
|
|
array->setBodyElement(t, i, element);
|
|
|
|
}
|
|
|
|
|
|
|
|
GcClassAddendum* addendum = getClassAddendum(t, class_, pool);
|
|
|
|
addendum->setBootstrapMethodTable(t, array);
|
2014-07-11 15:47:57 +00:00
|
|
|
} else if (vm::strcmp(reinterpret_cast<const int8_t*>("EnclosingMethod"),
|
|
|
|
name->body().begin()) == 0) {
|
2013-04-17 21:12:58 +00:00
|
|
|
int16_t enclosingClass = s.read2();
|
|
|
|
int16_t enclosingMethod = s.read2();
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClassAddendum* addendum = getClassAddendum(t, class_, pool);
|
2013-04-17 21:12:58 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
addendum->setEnclosingClass(
|
|
|
|
t,
|
2014-07-12 22:03:11 +00:00
|
|
|
cast<GcReference>(t, singletonObject(t, pool, enclosingClass - 1))
|
|
|
|
->name());
|
2013-04-17 21:12:58 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
addendum->setEnclosingMethod(
|
|
|
|
t,
|
2014-07-12 22:03:11 +00:00
|
|
|
enclosingMethod
|
|
|
|
? cast<GcPair>(t, singletonObject(t, pool, enclosingMethod - 1))
|
|
|
|
: 0);
|
2009-08-27 22:26:25 +00:00
|
|
|
} else {
|
|
|
|
s.skip(length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void updateClassTables(Thread* t, GcClass* newClass, GcClass* oldClass)
|
2007-11-05 21:40:17 +00:00
|
|
|
{
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* fieldTable = cast<GcArray>(t, newClass->fieldTable());
|
2007-11-05 21:40:17 +00:00
|
|
|
if (fieldTable) {
|
2014-06-29 05:48:17 +00:00
|
|
|
for (unsigned i = 0; i < fieldTable->length(); ++i) {
|
2014-06-26 01:42:16 +00:00
|
|
|
cast<GcField>(t, fieldTable->body()[i])->setClass(t, newClass);
|
2007-11-05 21:40:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
GcSingleton* staticTable = newClass->staticTable();
|
2012-10-06 21:25:12 +00:00
|
|
|
if (staticTable) {
|
2014-06-26 01:42:16 +00:00
|
|
|
staticTable->setBodyElement(t, 0, reinterpret_cast<uintptr_t>(newClass));
|
2012-10-06 21:25:12 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (newClass->flags() & ACC_INTERFACE) {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* virtualTable = cast<GcArray>(t, newClass->virtualTable());
|
2007-11-05 21:40:17 +00:00
|
|
|
if (virtualTable) {
|
2014-06-29 05:48:17 +00:00
|
|
|
for (unsigned i = 0; i < virtualTable->length(); ++i) {
|
2014-06-26 01:42:16 +00:00
|
|
|
GcMethod* m = cast<GcMethod>(t, virtualTable->body()[i]);
|
|
|
|
if (m->class_() == oldClass) {
|
|
|
|
m->setClass(t, newClass);
|
2007-11-05 21:40:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-03-16 16:54:35 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* methodTable = cast<GcArray>(t, newClass->methodTable());
|
2013-03-16 16:54:35 +00:00
|
|
|
if (methodTable) {
|
2014-06-29 05:48:17 +00:00
|
|
|
for (unsigned i = 0; i < methodTable->length(); ++i) {
|
2014-06-26 01:42:16 +00:00
|
|
|
cast<GcMethod>(t, methodTable->body()[i])->setClass(t, newClass);
|
2007-11-05 21:40:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void updateBootstrapClass(Thread* t, GcClass* bootstrapClass, GcClass* class_)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
|
|
|
expect(t, bootstrapClass != class_);
|
|
|
|
|
|
|
|
// verify that the classes have the same layout
|
2014-05-29 04:17:25 +00:00
|
|
|
expect(t, bootstrapClass->super() == class_->super());
|
2007-11-05 21:40:17 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
expect(t, bootstrapClass->fixedSize() >= class_->fixedSize());
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
expect(t, (class_->vmFlags() & HasFinalizerFlag) == 0);
|
2009-07-22 00:57:55 +00:00
|
|
|
|
2007-07-14 17:31:01 +00:00
|
|
|
PROTECT(t, bootstrapClass);
|
|
|
|
PROTECT(t, class_);
|
|
|
|
|
|
|
|
ENTER(t, Thread::ExclusiveState);
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
bootstrapClass->vmFlags() &= ~BootstrapFlag;
|
|
|
|
bootstrapClass->vmFlags() |= class_->vmFlags();
|
|
|
|
bootstrapClass->flags() |= class_->flags();
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
bootstrapClass->setArrayElementClass(t, class_->arrayElementClass());
|
|
|
|
bootstrapClass->setSuper(t, class_->super());
|
|
|
|
bootstrapClass->setInterfaceTable(t, class_->interfaceTable());
|
|
|
|
bootstrapClass->setVirtualTable(t, class_->virtualTable());
|
|
|
|
bootstrapClass->setFieldTable(t, class_->fieldTable());
|
|
|
|
bootstrapClass->setMethodTable(t, class_->methodTable());
|
|
|
|
bootstrapClass->setStaticTable(t, class_->staticTable());
|
|
|
|
bootstrapClass->setAddendum(t, class_->addendum());
|
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
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* makeArrayClass(Thread* t,
|
|
|
|
GcClassLoader* loader,
|
|
|
|
unsigned dimensions,
|
|
|
|
GcByteArray* spec,
|
|
|
|
GcClass* elementClass)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
2014-05-29 04:17:25 +00:00
|
|
|
if (type(t, GcJobject::Type)->vmFlags() & 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.
|
2014-07-11 15:47:57 +00:00
|
|
|
resolveSystemClass(
|
|
|
|
t, roots(t)->bootLoader(), type(t, GcJobject::Type)->name(), false);
|
2010-09-14 16:49:41 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* vtable = cast<GcArray>(t, type(t, GcJobject::Type)->virtualTable());
|
2007-11-05 21:40:17 +00:00
|
|
|
|
2017-02-01 15:07:11 +00:00
|
|
|
// From JDK docs: for array classes the public, private, protected modifiers are the same as
|
|
|
|
// the underlying type, and the final modifier is always set. Testing on OpenJDK shows that
|
|
|
|
// ACC_ABSTRACT is also set on array classes.
|
|
|
|
int flags = elementClass->flags() & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED);
|
|
|
|
flags |= ACC_FINAL;
|
|
|
|
flags |= ACC_ABSTRACT;
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* c = t->m->processor->makeClass(t,
|
2017-02-01 15:07:11 +00:00
|
|
|
flags,
|
2014-07-11 15:47:57 +00:00
|
|
|
0,
|
|
|
|
2 * BytesPerWord,
|
|
|
|
BytesPerWord,
|
|
|
|
dimensions,
|
|
|
|
elementClass,
|
|
|
|
type(t, GcArray::Type)->objectMask(),
|
|
|
|
spec,
|
|
|
|
0,
|
|
|
|
type(t, GcJobject::Type),
|
|
|
|
roots(t)->arrayInterfaceTable(),
|
|
|
|
vtable,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
loader,
|
|
|
|
vtable->length());
|
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
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void saveLoadedClass(Thread* t, GcClassLoader* loader, GcClass* c)
|
2011-03-27 05:21:37 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, loader);
|
|
|
|
PROTECT(t, c);
|
|
|
|
|
|
|
|
ACQUIRE(t, t->m->classLock);
|
|
|
|
|
2014-06-28 21:11:31 +00:00
|
|
|
if (loader->map() == 0) {
|
2014-05-29 04:17:25 +00:00
|
|
|
GcHashMap* map = makeHashMap(t, 0, 0);
|
2014-07-02 21:11:27 +00:00
|
|
|
loader->setMap(t, map);
|
2011-03-27 05:21:37 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
hashMapInsert(
|
|
|
|
t, cast<GcHashMap>(t, loader->map()), c->name(), c, byteArrayHash);
|
2011-03-27 05:21:37 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* makeArrayClass(Thread* t,
|
|
|
|
GcClassLoader* loader,
|
|
|
|
GcByteArray* spec,
|
|
|
|
bool throw_,
|
|
|
|
Gc::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);
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
const char* s = reinterpret_cast<const char*>(spec->body().begin());
|
2007-07-14 17:31:01 +00:00
|
|
|
const char* start = s;
|
|
|
|
unsigned dimensions = 0;
|
2014-07-11 15:50:18 +00:00
|
|
|
for (; *s == '['; ++s)
|
|
|
|
++dimensions;
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
GcByteArray* elementSpec;
|
2007-07-14 17:31:01 +00:00
|
|
|
switch (*s) {
|
|
|
|
case 'L': {
|
2014-07-11 15:50:18 +00:00
|
|
|
++s;
|
2007-07-14 17:31:01 +00:00
|
|
|
const char* elementSpecStart = s;
|
2014-07-11 15:50:18 +00:00
|
|
|
while (*s and *s != ';')
|
|
|
|
++s;
|
2013-10-25 18:23:03 +00:00
|
|
|
if (dimensions > 1) {
|
|
|
|
elementSpecStart -= dimensions;
|
2014-07-11 15:50:18 +00:00
|
|
|
++s;
|
2013-10-25 18:23:03 +00:00
|
|
|
}
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
elementSpec = makeByteArray(t, s - elementSpecStart + 1);
|
|
|
|
memcpy(elementSpec->body().begin(),
|
|
|
|
&spec->body()[elementSpecStart - start],
|
2007-07-14 17:31:01 +00:00
|
|
|
s - elementSpecStart);
|
2014-06-28 23:24:24 +00:00
|
|
|
elementSpec->body()[s - elementSpecStart] = 0;
|
2007-07-14 17:31:01 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
if (dimensions > 1) {
|
|
|
|
char c = *s;
|
2014-06-28 23:24:24 +00:00
|
|
|
elementSpec = makeByteArray(t, dimensions + 1);
|
2013-04-23 03:28:25 +00:00
|
|
|
unsigned i;
|
|
|
|
for (i = 0; i < dimensions - 1; ++i) {
|
2014-07-11 15:47:57 +00:00
|
|
|
elementSpec->body()[i] = '[';
|
2013-04-23 03:28:25 +00:00
|
|
|
}
|
2014-06-28 23:24:24 +00:00
|
|
|
elementSpec->body()[i++] = c;
|
|
|
|
elementSpec->body()[i] = 0;
|
2014-07-11 15:50:18 +00:00
|
|
|
--dimensions;
|
2007-07-14 17:31:01 +00:00
|
|
|
} else {
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* elementClass
|
|
|
|
= cast<GcClass>(t,
|
|
|
|
hashMapFind(t,
|
|
|
|
roots(t)->bootstrapClassMap(),
|
|
|
|
elementSpec,
|
|
|
|
byteArrayHash,
|
|
|
|
byteArrayEqual));
|
|
|
|
|
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);
|
2014-07-11 15:50:18 +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);
|
|
|
|
|
2014-06-28 21:11:31 +00:00
|
|
|
GcClass* class_ = findLoadedClass(t, elementClass->loader(), spec);
|
2011-03-27 05:21:37 +00:00
|
|
|
if (class_) {
|
|
|
|
return class_;
|
|
|
|
}
|
2010-09-15 00:52:57 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
class_ = makeArrayClass(
|
|
|
|
t, elementClass->loader(), dimensions, spec, elementClass);
|
2011-03-27 05:21:37 +00:00
|
|
|
|
|
|
|
PROTECT(t, class_);
|
|
|
|
|
2014-06-28 21:11:31 +00:00
|
|
|
saveLoadedClass(t, elementClass->loader(), class_);
|
2011-03-27 05:21:37 +00:00
|
|
|
|
|
|
|
return class_;
|
2009-08-10 13:56:16 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* resolveArrayClass(Thread* t,
|
|
|
|
GcClassLoader* loader,
|
|
|
|
GcByteArray* spec,
|
|
|
|
bool throw_,
|
|
|
|
Gc::Type throwType)
|
2009-08-10 13:56:16 +00:00
|
|
|
{
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* c = cast<GcClass>(t,
|
|
|
|
hashMapFind(t,
|
2014-06-30 01:44:41 +00:00
|
|
|
roots(t)->bootstrapClassMap(),
|
2014-07-02 21:11:27 +00:00
|
|
|
spec,
|
2014-05-29 04:17:25 +00:00
|
|
|
byteArrayHash,
|
|
|
|
byteArrayEqual));
|
2009-08-10 13:56:16 +00:00
|
|
|
|
|
|
|
if (c) {
|
2014-06-26 01:42:16 +00:00
|
|
|
c->setVirtualTable(t, type(t, GcJobject::Type)->virtualTable());
|
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);
|
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
c = findLoadedClass(t, roots(t)->bootLoader(), spec);
|
2011-01-17 16:36:03 +00:00
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void removeMonitor(Thread* t, object o)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
2008-01-19 20:12:16 +00:00
|
|
|
unsigned hash;
|
|
|
|
if (DebugMonitors) {
|
|
|
|
hash = objectHash(t, o);
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
object m
|
|
|
|
= hashMapRemove(t, roots(t)->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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void removeString(Thread* t, object o)
|
2007-07-29 00:02:32 +00:00
|
|
|
{
|
2014-06-30 01:44:41 +00:00
|
|
|
hashMapRemove(t, roots(t)->stringMap(), o, stringHash, objectEqual);
|
2007-09-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void bootClass(Thread* t,
|
|
|
|
Gc::Type type,
|
|
|
|
int superType,
|
2015-03-12 14:37:49 +00:00
|
|
|
uint32_t* objectMask,
|
2014-07-11 15:47:57 +00:00
|
|
|
unsigned fixedSize,
|
|
|
|
unsigned arrayElementSize,
|
|
|
|
unsigned vtableLength)
|
2007-11-04 21:15:28 +00:00
|
|
|
{
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* super
|
|
|
|
= (superType >= 0 ? vm::type(t, static_cast<Gc::Type>(superType)) : 0);
|
2007-11-06 15:29:05 +00:00
|
|
|
|
2015-03-12 14:37:49 +00:00
|
|
|
unsigned maskSize
|
|
|
|
= ceilingDivide(fixedSize + arrayElementSize, 32 * BytesPerWord);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcIntArray* mask;
|
2007-11-04 21:15:28 +00:00
|
|
|
if (objectMask) {
|
2014-07-11 15:47:57 +00:00
|
|
|
if (super and super->objectMask()
|
2015-03-12 14:37:49 +00:00
|
|
|
and super->objectMask()->length() == maskSize
|
|
|
|
and memcmp(super->objectMask()->body().begin(),
|
|
|
|
objectMask,
|
|
|
|
sizeof(uint32_t) * maskSize) == 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
mask = vm::type(t, static_cast<Gc::Type>(superType))->objectMask();
|
2007-11-06 15:29:05 +00:00
|
|
|
} else {
|
2015-03-12 14:37:49 +00:00
|
|
|
mask = makeIntArray(t, maskSize);
|
|
|
|
memcpy(mask->body().begin(), objectMask, sizeof(uint32_t) * maskSize);
|
2007-11-06 15:29:05 +00:00
|
|
|
}
|
2007-11-04 21:15:28 +00:00
|
|
|
} else {
|
|
|
|
mask = 0;
|
|
|
|
}
|
|
|
|
|
2017-02-01 15:07:11 +00:00
|
|
|
int flags = 0;
|
|
|
|
switch(type) {
|
|
|
|
case Gc::JbyteType:
|
|
|
|
case Gc::JintType:
|
|
|
|
case Gc::JshortType:
|
|
|
|
case Gc::JlongType:
|
|
|
|
case Gc::JbooleanType:
|
|
|
|
case Gc::JcharType:
|
|
|
|
case Gc::JfloatType:
|
|
|
|
case Gc::JdoubleType:
|
|
|
|
|
|
|
|
case Gc::ByteArrayType:
|
|
|
|
case Gc::IntArrayType:
|
|
|
|
case Gc::ShortArrayType:
|
|
|
|
case Gc::LongArrayType:
|
|
|
|
case Gc::BooleanArrayType:
|
|
|
|
case Gc::CharArrayType:
|
|
|
|
case Gc::FloatArrayType:
|
|
|
|
case Gc::DoubleArrayType:
|
|
|
|
// Primitive and array types are final, abstract and public.
|
|
|
|
flags = ACC_FINAL | ACC_ABSTRACT | ACC_PUBLIC;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
super = (superType >= 0 ? vm::type(t, static_cast<Gc::Type>(superType)) : 0);
|
|
|
|
|
|
|
|
GcClass* class_ = t->m->processor->makeClass(t,
|
2017-02-01 15:07:11 +00:00
|
|
|
flags,
|
2014-07-11 15:47:57 +00:00
|
|
|
BootstrapFlag,
|
|
|
|
fixedSize,
|
|
|
|
arrayElementSize,
|
|
|
|
arrayElementSize ? 1 : 0,
|
|
|
|
0,
|
|
|
|
mask,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
super,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
roots(t)->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
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void bootJavaClass(Thread* t,
|
|
|
|
Gc::Type type,
|
|
|
|
int superType,
|
|
|
|
const char* name,
|
|
|
|
int vtableLength,
|
|
|
|
object bootMethod)
|
2007-11-04 21:15:28 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, bootMethod);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* n = makeByteArray(t, name);
|
2010-12-10 05:17:57 +00:00
|
|
|
PROTECT(t, n);
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* class_ = vm::type(t, type);
|
2010-12-10 05:17:57 +00:00
|
|
|
PROTECT(t, class_);
|
2007-11-04 21:15:28 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
class_->setName(t, n);
|
2007-11-04 21:15:28 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* vtable;
|
2007-11-05 14:28:46 +00:00
|
|
|
if (vtableLength >= 0) {
|
2014-06-29 05:48:17 +00:00
|
|
|
vtable = makeArray(t, vtableLength);
|
2014-07-11 15:50:18 +00:00
|
|
|
for (int i = 0; i < vtableLength; ++i) {
|
2014-06-26 01:42:16 +00:00
|
|
|
vtable->setBodyElement(t, i, bootMethod);
|
2007-11-05 14:28:46 +00:00
|
|
|
}
|
|
|
|
} else {
|
2014-07-11 15:47:57 +00:00
|
|
|
vtable = cast<GcArray>(
|
|
|
|
t, vm::type(t, static_cast<Gc::Type>(superType))->virtualTable());
|
2007-11-04 21:15:28 +00:00
|
|
|
}
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
class_->setVirtualTable(t, vtable);
|
2007-11-04 21:15:28 +00:00
|
|
|
|
2007-12-11 21:26:59 +00:00
|
|
|
t->m->processor->initVtable(t, class_);
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
hashMapInsert(t, roots(t)->bootstrapClassMap(), n, class_, byteArrayHash);
|
2007-11-04 21:15:28 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void nameClass(Thread* t, Gc::Type type, const char* name)
|
2010-11-16 16:31:49 +00:00
|
|
|
{
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* n = makeByteArray(t, name);
|
2014-06-26 01:42:16 +00:00
|
|
|
cast<GcClass>(t, t->m->types->body()[type])->setName(t, n);
|
2010-11-16 16:31:49 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void makeArrayInterfaceTable(Thread* t)
|
2013-03-15 19:25:12 +00:00
|
|
|
{
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* interfaceTable = makeArray(t, 4);
|
2014-06-26 01:42:16 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
interfaceTable->setBodyElement(t, 0, type(t, GcSerializable::Type));
|
2014-06-26 01:42:16 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
interfaceTable->setBodyElement(t, 2, type(t, GcCloneable::Type));
|
2014-06-26 01:42:16 +00:00
|
|
|
|
|
|
|
roots(t)->setArrayInterfaceTable(t, interfaceTable);
|
2013-03-15 19:25:12 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void boot(Thread* t)
|
2008-11-28 22:02:45 +00:00
|
|
|
{
|
|
|
|
Machine* m = t->m;
|
|
|
|
|
2008-11-29 23:08:14 +00:00
|
|
|
m->unsafe = true;
|
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
m->roots = reinterpret_cast<GcRoots*>(allocate(t, GcRoots::FixedSize, true));
|
2010-09-14 16:49:41 +00:00
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
object classLoader = allocate(t, GcSystemClassLoader::FixedSize, true);
|
|
|
|
// sequence point, for gc (don't recombine statements)
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(t)->setBootLoader(t, reinterpret_cast<GcClassLoader*>(classLoader));
|
2010-09-14 16:49:41 +00:00
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
classLoader = allocate(t, GcSystemClassLoader::FixedSize, true);
|
|
|
|
// sequence point, for gc (don't recombine statements)
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(t)->setAppLoader(t, reinterpret_cast<GcClassLoader*>(classLoader));
|
2008-11-28 22:02:45 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
m->types = reinterpret_cast<GcArray*>(
|
|
|
|
allocate(t, pad((TypeCount + 2) * BytesPerWord), true));
|
2014-06-28 23:24:24 +00:00
|
|
|
m->types->length() = TypeCount;
|
2008-11-28 22:02:45 +00:00
|
|
|
|
|
|
|
#include "type-initializations.cpp"
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* arrayClass = type(t, GcArray::Type);
|
2014-06-26 02:17:27 +00:00
|
|
|
setField(t, m->types, 0, arrayClass);
|
2014-06-30 01:44:41 +00:00
|
|
|
|
|
|
|
GcClass* rootsClass = type(t, GcRoots::Type);
|
2014-06-26 02:17:27 +00:00
|
|
|
setField(t, m->roots, 0, rootsClass);
|
2008-11-28 22:02:45 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* loaderClass = type(t, GcSystemClassLoader::Type);
|
2014-06-26 02:17:27 +00:00
|
|
|
setField(t, roots(t)->bootLoader(), 0, loaderClass);
|
|
|
|
setField(t, roots(t)->appLoader(), 0, loaderClass);
|
2008-11-28 22:02:45 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* objectClass = type(t, GcJobject::Type);
|
2009-12-25 00:57:07 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* classClass = type(t, GcClass::Type);
|
2014-06-26 02:17:27 +00:00
|
|
|
setField(t, classClass, 0, classClass);
|
2014-06-26 01:42:16 +00:00
|
|
|
classClass->setSuper(t, objectClass);
|
2008-11-28 22:02:45 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* intArrayClass = type(t, GcIntArray::Type);
|
2014-06-26 02:17:27 +00:00
|
|
|
setField(t, intArrayClass, 0, classClass);
|
2014-06-26 01:42:16 +00:00
|
|
|
intArrayClass->setSuper(t, objectClass);
|
2008-11-28 22:02:45 +00:00
|
|
|
|
|
|
|
m->unsafe = false;
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
type(t, GcSingleton::Type)->vmFlags() |= SingletonFlag;
|
|
|
|
|
|
|
|
type(t, GcContinuation::Type)->vmFlags() |= ContinuationFlag;
|
|
|
|
|
|
|
|
type(t, GcJreference::Type)->vmFlags() |= ReferenceFlag;
|
|
|
|
type(t, GcWeakReference::Type)->vmFlags() |= ReferenceFlag
|
|
|
|
| WeakReferenceFlag;
|
|
|
|
type(t, GcSoftReference::Type)->vmFlags() |= ReferenceFlag
|
|
|
|
| WeakReferenceFlag;
|
|
|
|
type(t, GcPhantomReference::Type)->vmFlags() |= ReferenceFlag
|
|
|
|
| WeakReferenceFlag;
|
|
|
|
|
|
|
|
type(t, GcJboolean::Type)->vmFlags() |= PrimitiveFlag;
|
|
|
|
type(t, GcJbyte::Type)->vmFlags() |= PrimitiveFlag;
|
|
|
|
type(t, GcJchar::Type)->vmFlags() |= PrimitiveFlag;
|
|
|
|
type(t, GcJshort::Type)->vmFlags() |= PrimitiveFlag;
|
|
|
|
type(t, GcJint::Type)->vmFlags() |= PrimitiveFlag;
|
|
|
|
type(t, GcJlong::Type)->vmFlags() |= PrimitiveFlag;
|
|
|
|
type(t, GcJfloat::Type)->vmFlags() |= PrimitiveFlag;
|
|
|
|
type(t, GcJdouble::Type)->vmFlags() |= PrimitiveFlag;
|
|
|
|
type(t, GcJvoid::Type)->vmFlags() |= PrimitiveFlag;
|
|
|
|
|
|
|
|
type(t, GcBooleanArray::Type)
|
|
|
|
->setArrayElementClass(t, type(t, GcJboolean::Type));
|
2014-06-26 01:42:16 +00:00
|
|
|
type(t, GcByteArray::Type)->setArrayElementClass(t, type(t, GcJbyte::Type));
|
|
|
|
type(t, GcCharArray::Type)->setArrayElementClass(t, type(t, GcJchar::Type));
|
|
|
|
type(t, GcShortArray::Type)->setArrayElementClass(t, type(t, GcJshort::Type));
|
|
|
|
type(t, GcIntArray::Type)->setArrayElementClass(t, type(t, GcJint::Type));
|
|
|
|
type(t, GcLongArray::Type)->setArrayElementClass(t, type(t, GcJlong::Type));
|
|
|
|
type(t, GcFloatArray::Type)->setArrayElementClass(t, type(t, GcJfloat::Type));
|
2014-07-11 15:47:57 +00:00
|
|
|
type(t, GcDoubleArray::Type)
|
|
|
|
->setArrayElementClass(t, type(t, GcJdouble::Type));
|
2014-05-29 04:17:25 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
{
|
|
|
|
GcHashMap* map = makeHashMap(t, 0, 0);
|
2014-07-02 21:11:27 +00:00
|
|
|
roots(t)->bootLoader()->setMap(t, map);
|
2010-09-22 19:58:46 +00:00
|
|
|
}
|
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
roots(t)->bootLoader()->as<GcSystemClassLoader>(t)->finder() = m->bootFinder;
|
2010-09-14 16:49:41 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
{
|
|
|
|
GcHashMap* map = makeHashMap(t, 0, 0);
|
2014-07-02 21:11:27 +00:00
|
|
|
roots(t)->appLoader()->setMap(t, map);
|
2010-09-14 16:49:41 +00:00
|
|
|
}
|
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
roots(t)->appLoader()->as<GcSystemClassLoader>(t)->finder() = m->appFinder;
|
2010-09-22 19:58:46 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(t)->appLoader()->setParent(t, roots(t)->bootLoader());
|
2010-09-14 16:49:41 +00:00
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
{
|
|
|
|
GcHashMap* map = makeHashMap(t, 0, 0);
|
|
|
|
// sequence point, for gc (don't recombine statements)
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(t)->setBootstrapClassMap(t, map);
|
2014-06-30 01:44:41 +00:00
|
|
|
}
|
2010-09-14 16:49:41 +00:00
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
{
|
|
|
|
GcWeakHashMap* map = makeWeakHashMap(t, 0, 0);
|
|
|
|
// sequence point, for gc (don't recombine statements)
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(t)->setStringMap(t, map->as<GcHashMap>(t));
|
2014-06-30 01:44:41 +00:00
|
|
|
}
|
2010-12-27 22:55:23 +00:00
|
|
|
|
2013-03-15 19:25:12 +00:00
|
|
|
makeArrayInterfaceTable(t);
|
2013-02-21 22:37:17 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
type(t, GcBooleanArray::Type)
|
|
|
|
->setInterfaceTable(t, roots(t)->arrayInterfaceTable());
|
|
|
|
type(t, GcByteArray::Type)
|
|
|
|
->setInterfaceTable(t, roots(t)->arrayInterfaceTable());
|
|
|
|
type(t, GcCharArray::Type)
|
|
|
|
->setInterfaceTable(t, roots(t)->arrayInterfaceTable());
|
|
|
|
type(t, GcShortArray::Type)
|
|
|
|
->setInterfaceTable(t, roots(t)->arrayInterfaceTable());
|
|
|
|
type(t, GcIntArray::Type)
|
|
|
|
->setInterfaceTable(t, roots(t)->arrayInterfaceTable());
|
|
|
|
type(t, GcLongArray::Type)
|
|
|
|
->setInterfaceTable(t, roots(t)->arrayInterfaceTable());
|
|
|
|
type(t, GcFloatArray::Type)
|
|
|
|
->setInterfaceTable(t, roots(t)->arrayInterfaceTable());
|
|
|
|
type(t, GcDoubleArray::Type)
|
|
|
|
->setInterfaceTable(t, roots(t)->arrayInterfaceTable());
|
2013-02-21 22:37:17 +00:00
|
|
|
|
2011-09-20 22:30:30 +00:00
|
|
|
m->processor->boot(t, 0, 0);
|
2008-12-04 02:09:57 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
{
|
|
|
|
GcCode* bootCode = makeCode(t, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
2014-06-29 05:48:17 +00:00
|
|
|
bootCode->body()[0] = impdep1;
|
2014-07-11 15:50:18 +00:00
|
|
|
object bootMethod
|
|
|
|
= makeMethod(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);
|
|
|
|
|
2015-05-02 02:10:33 +00:00
|
|
|
# include "type-java-initializations.cpp"
|
|
|
|
# include "type-name-initializations.cpp"
|
2010-11-16 16:31:49 +00:00
|
|
|
|
2008-11-28 22:02:45 +00:00
|
|
|
}
|
2015-05-02 02:10:33 +00:00
|
|
|
|
2008-11-28 22:02:45 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
class HeapClient : public Heap::Client {
|
2007-10-28 19:14:53 +00:00
|
|
|
public:
|
2014-07-11 15:50:18 +00:00
|
|
|
HeapClient(Machine* m) : m(m)
|
|
|
|
{
|
|
|
|
}
|
2007-10-28 19:14:53 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +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
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
virtual bool isFixed(void* p)
|
|
|
|
{
|
2007-10-28 19:14:53 +00:00
|
|
|
return objectFixed(m->rootThread, static_cast<object>(p));
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
virtual unsigned sizeInWords(void* p)
|
|
|
|
{
|
2007-10-28 19:14:53 +00:00
|
|
|
Thread* t = m->rootThread;
|
|
|
|
|
2013-02-11 00:14:16 +00:00
|
|
|
object o = static_cast<object>(m->heap->follow(maskAlignedPointer(p)));
|
2007-10-28 19:14:53 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
unsigned n = baseSize(t, o, m->heap->follow(objectClass(t, o)));
|
2007-10-28 19:14:53 +00:00
|
|
|
|
|
|
|
if (objectExtended(t, o)) {
|
2014-07-11 15:50:18 +00:00
|
|
|
++n;
|
2007-10-28 19:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
virtual unsigned copiedSizeInWords(void* p)
|
|
|
|
{
|
2007-10-28 19:14:53 +00:00
|
|
|
Thread* t = m->rootThread;
|
|
|
|
|
2013-02-11 00:14:16 +00:00
|
|
|
object o = static_cast<object>(m->heap->follow(maskAlignedPointer(p)));
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, not objectFixed(t, o));
|
2007-10-28 19:14:53 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
unsigned n = baseSize(t, o, m->heap->follow(objectClass(t, o)));
|
2007-10-28 19:14:53 +00:00
|
|
|
|
|
|
|
if (objectExtended(t, o) or hashTaken(t, o)) {
|
2014-07-11 15:50:18 +00:00
|
|
|
++n;
|
2007-10-28 19:14:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
virtual void copy(void* srcp, void* dstp)
|
|
|
|
{
|
2007-10-28 19:14:53 +00:00
|
|
|
Thread* t = m->rootThread;
|
|
|
|
|
2013-02-11 00:14:16 +00:00
|
|
|
object src = static_cast<object>(m->heap->follow(maskAlignedPointer(srcp)));
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, not objectFixed(t, src));
|
2007-10-28 19:14:53 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcClass* class_ = m->heap->follow(objectClass(t, src));
|
2007-10-28 19:14:53 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
virtual void walk(void* p, Heap::Walker* w)
|
|
|
|
{
|
2013-02-11 00:14:16 +00:00
|
|
|
object o = static_cast<object>(m->heap->follow(maskAlignedPointer(p)));
|
2008-11-11 15:20:49 +00:00
|
|
|
::walk(m->rootThread, w, o, 0);
|
2007-10-28 19:14:53 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +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
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
|
2007-10-28 19:14:53 +00:00
|
|
|
private:
|
|
|
|
Machine* m;
|
|
|
|
};
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void doCollect(Thread* t, Heap::CollectionType type, int pendingAllocation)
|
2010-12-27 22:55:23 +00:00
|
|
|
{
|
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
|
2014-08-20 15:49:00 +00:00
|
|
|
bool stress = (t->getFlags() & Thread::StressFlag) != 0;
|
2014-07-11 15:50:18 +00:00
|
|
|
if (not stress)
|
2014-08-20 15:49:00 +00:00
|
|
|
t->setFlag(Thread::StressFlag);
|
2010-12-27 22:55:23 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
Machine* m = t->m;
|
|
|
|
|
|
|
|
m->unsafe = true;
|
2014-07-11 15:50:18 +00:00
|
|
|
m->heap->collect(
|
|
|
|
type,
|
|
|
|
footprint(m->rootThread),
|
|
|
|
pendingAllocation - (t->m->heapPoolIndex * ThreadHeapSizeInWords));
|
2010-12-27 22:55:23 +00:00
|
|
|
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
|
2014-07-11 15:50:18 +00:00
|
|
|
if (not stress)
|
2014-08-20 15:49:00 +00:00
|
|
|
t->clearFlag(Thread::StressFlag);
|
2010-12-27 22:55:23 +00:00
|
|
|
#endif
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcFinalizer* finalizeQueue = t->m->finalizeQueue;
|
2010-12-27 22:55:23 +00:00
|
|
|
t->m->finalizeQueue = 0;
|
2014-07-11 15:47:57 +00:00
|
|
|
for (; finalizeQueue;
|
|
|
|
finalizeQueue = cast<GcFinalizer>(t, finalizeQueue->next())) {
|
2010-12-27 22:55:23 +00:00
|
|
|
void (*function)(Thread*, object);
|
2014-06-29 05:48:17 +00:00
|
|
|
memcpy(&function, &finalizeQueue->finalize(), BytesPerWord);
|
|
|
|
function(t, finalizeQueue->target());
|
2010-12-27 22:55:23 +00:00
|
|
|
}
|
|
|
|
|
2017-01-19 16:55:54 +00:00
|
|
|
#ifndef SGX
|
2014-06-30 01:44:41 +00:00
|
|
|
if ((roots(t)->objectsToFinalize() or roots(t)->objectsToClean())
|
2014-07-11 15:47:57 +00:00
|
|
|
and m->finalizeThread == 0 and t->state != Thread::ExitState) {
|
|
|
|
m->finalizeThread = m->processor->makeThread(
|
|
|
|
m, roots(t)->finalizerThread(), m->rootThread);
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
addThread(t, m->finalizeThread);
|
|
|
|
|
|
|
|
if (not startThread(t, m->finalizeThread)) {
|
|
|
|
removeThread(t, m->finalizeThread);
|
|
|
|
m->finalizeThread = 0;
|
|
|
|
}
|
|
|
|
}
|
2017-01-19 16:55:54 +00:00
|
|
|
#endif
|
2010-12-27 22:55:23 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
uint64_t invokeLoadClass(Thread* t, uintptr_t* arguments)
|
2011-03-15 23:52:02 +00:00
|
|
|
{
|
2014-05-29 04:17:25 +00:00
|
|
|
GcMethod* method = cast<GcMethod>(t, reinterpret_cast<object>(arguments[0]));
|
2011-03-15 23:52:02 +00:00
|
|
|
object loader = reinterpret_cast<object>(arguments[1]);
|
|
|
|
object specString = reinterpret_cast<object>(arguments[2]);
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
return reinterpret_cast<uintptr_t>(
|
|
|
|
t->m->processor->invoke(t, method, loader, specString));
|
2011-03-15 23:52:02 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
bool isInitializing(Thread* t, GcClass* c)
|
2011-04-01 01:43:49 +00:00
|
|
|
{
|
|
|
|
for (Thread::ClassInitStack* s = t->classInitStack; s; s = s->next) {
|
|
|
|
if (s->class_ == c) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
object findInTable(Thread* t,
|
|
|
|
GcArray* table,
|
|
|
|
GcByteArray* name,
|
|
|
|
GcByteArray* spec,
|
|
|
|
GcByteArray* (*getName)(Thread*, object),
|
|
|
|
GcByteArray* (*getSpec)(Thread*, object))
|
2012-03-27 00:06:16 +00:00
|
|
|
{
|
|
|
|
if (table) {
|
2014-06-29 05:48:17 +00:00
|
|
|
for (unsigned i = 0; i < table->length(); ++i) {
|
|
|
|
object o = table->body()[i];
|
2014-07-11 15:47:57 +00:00
|
|
|
if (vm::strcmp(getName(t, o)->body().begin(), name->body().begin()) == 0
|
|
|
|
and vm::strcmp(getSpec(t, o)->body().begin(), spec->body().begin())
|
|
|
|
== 0) {
|
2012-03-27 00:06:16 +00:00
|
|
|
return o;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-12 16:16:03 +00:00
|
|
|
if (false) {
|
|
|
|
fprintf(
|
|
|
|
stderr, "%s %s not in\n", name->body().begin(), spec->body().begin());
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < table->length(); ++i) {
|
|
|
|
object o = table->body()[i];
|
|
|
|
fprintf(stderr,
|
|
|
|
"\t%s %s\n",
|
|
|
|
getName(t, o)->body().begin(),
|
|
|
|
getSpec(t, o)->body().begin());
|
|
|
|
}
|
|
|
|
}
|
2012-03-27 00:06:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void updatePackageMap(Thread* t, GcClass* class_)
|
2014-03-19 17:21:26 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, class_);
|
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
if (roots(t)->packageMap() == 0) {
|
|
|
|
GcHashMap* map = makeHashMap(t, 0, 0);
|
|
|
|
// sequence point, for gc (don't recombine statements)
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(t)->setPackageMap(t, map);
|
2014-03-19 17:21:26 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* className = class_->name();
|
|
|
|
if ('[' != className->body()[0]) {
|
2014-07-11 15:47:57 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, packageName, className->length());
|
2014-03-19 17:21:26 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
char* s = reinterpret_cast<char*>(className->body().begin());
|
2014-03-19 17:21:26 +00:00
|
|
|
char* p = strrchr(s, '/');
|
|
|
|
|
|
|
|
if (p) {
|
|
|
|
int length = (p - s) + 1;
|
2014-07-11 15:47:57 +00:00
|
|
|
memcpy(
|
|
|
|
RUNTIME_ARRAY_BODY(packageName), className->body().begin(), length);
|
2014-03-19 17:21:26 +00:00
|
|
|
RUNTIME_ARRAY_BODY(packageName)[length] = 0;
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcByteArray* key
|
|
|
|
= vm::makeByteArray(t, "%s", RUNTIME_ARRAY_BODY(packageName));
|
2014-03-19 17:21:26 +00:00
|
|
|
PROTECT(t, key);
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
hashMapRemove(
|
|
|
|
t, roots(t)->packageMap(), key, byteArrayHash, byteArrayEqual);
|
2014-03-19 17:21:26 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* source = class_->source();
|
2014-03-19 17:21:26 +00:00
|
|
|
if (source) {
|
|
|
|
// note that we strip the "file:" prefix, since OpenJDK's
|
|
|
|
// Package.defineSystemPackage expects an unadorned filename:
|
|
|
|
const unsigned PrefixLength = 5;
|
2014-07-11 15:47:57 +00:00
|
|
|
unsigned sourceNameLength = source->length() - PrefixLength;
|
2014-03-19 17:21:26 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, sourceName, sourceNameLength);
|
|
|
|
memcpy(RUNTIME_ARRAY_BODY(sourceName),
|
2014-06-29 05:48:17 +00:00
|
|
|
&source->body()[PrefixLength],
|
2014-03-19 17:21:26 +00:00
|
|
|
sourceNameLength);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
source = vm::makeByteArray(t, "%s", RUNTIME_ARRAY_BODY(sourceName));
|
2014-03-19 17:21:26 +00:00
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
source = vm::makeByteArray(t, "avian-dummy-package-source");
|
2014-03-19 17:21:26 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
hashMapInsert(t, roots(t)->packageMap(), key, source, byteArrayHash);
|
2014-03-19 17:21:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
} // namespace
|
2007-07-06 23:50:26 +00:00
|
|
|
|
|
|
|
namespace vm {
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
Machine::Machine(System* system,
|
|
|
|
Heap* heap,
|
|
|
|
Finder* bootFinder,
|
|
|
|
Finder* appFinder,
|
|
|
|
Processor* processor,
|
|
|
|
Classpath* classpath,
|
|
|
|
const char** properties,
|
|
|
|
unsigned propertyCount,
|
|
|
|
const char** arguments,
|
|
|
|
unsigned argumentCount,
|
|
|
|
unsigned stackSizeInBytes)
|
|
|
|
: vtable(&javaVMVTable),
|
|
|
|
system(system),
|
|
|
|
heapClient(new (heap->allocate(sizeof(HeapClient))) HeapClient(this)),
|
|
|
|
heap(heap),
|
|
|
|
bootFinder(bootFinder),
|
|
|
|
appFinder(appFinder),
|
|
|
|
processor(processor),
|
|
|
|
classpath(classpath),
|
|
|
|
rootThread(0),
|
|
|
|
exclusive(0),
|
|
|
|
finalizeThread(0),
|
|
|
|
jniReferences(0),
|
|
|
|
propertyCount(propertyCount),
|
|
|
|
arguments(arguments),
|
|
|
|
argumentCount(argumentCount),
|
|
|
|
threadCount(0),
|
|
|
|
activeCount(0),
|
|
|
|
liveCount(0),
|
|
|
|
daemonCount(0),
|
|
|
|
fixedFootprint(0),
|
|
|
|
stackSizeInBytes(stackSizeInBytes),
|
|
|
|
localThread(0),
|
|
|
|
stateLock(0),
|
|
|
|
heapLock(0),
|
|
|
|
classLock(0),
|
|
|
|
referenceLock(0),
|
|
|
|
shutdownLock(0),
|
|
|
|
libraries(0),
|
|
|
|
errorLog(0),
|
|
|
|
bootimage(0),
|
|
|
|
types(0),
|
|
|
|
roots(0),
|
|
|
|
finalizers(0),
|
|
|
|
tenuredFinalizers(0),
|
|
|
|
finalizeQueue(0),
|
|
|
|
weakReferences(0),
|
|
|
|
tenuredWeakReferences(0),
|
|
|
|
unsafe(false),
|
|
|
|
collecting(false),
|
|
|
|
triedBuiltinOnLoad(false),
|
|
|
|
dumpedHeapOnOOM(false),
|
|
|
|
alive(true),
|
|
|
|
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
|
|
|
|
2014-04-09 06:16:53 +00:00
|
|
|
// Copying the properties memory (to avoid memory crashes)
|
|
|
|
this->properties = (char**)heap->allocate(sizeof(char*) * propertyCount);
|
2014-07-11 15:50:18 +00:00
|
|
|
for (unsigned int i = 0; i < propertyCount; i++) {
|
|
|
|
size_t length = strlen(properties[i]) + 1; // +1 for null-terminating char
|
2014-04-09 21:02:11 +00:00
|
|
|
this->properties[i] = (char*)heap->allocate(sizeof(char) * length);
|
|
|
|
memcpy(this->properties[i], properties[i], length);
|
2014-04-09 06:16:53 +00:00
|
|
|
}
|
|
|
|
|
2014-04-09 12:02:48 +00:00
|
|
|
const char* bootstrapProperty = findProperty(this, BOOTSTRAP_PROPERTY);
|
2014-07-11 15:50:18 +00:00
|
|
|
const char* bootstrapPropertyDup
|
|
|
|
= bootstrapProperty ? strdup(bootstrapProperty) : 0;
|
|
|
|
const char* bootstrapPropertyEnd
|
|
|
|
= bootstrapPropertyDup
|
|
|
|
+ (bootstrapPropertyDup ? strlen(bootstrapPropertyDup) : 0);
|
2014-04-09 12:02:48 +00:00
|
|
|
char* codeLibraryName = (char*)bootstrapPropertyDup;
|
|
|
|
char* codeLibraryNameEnd = 0;
|
2014-07-11 15:50:18 +00:00
|
|
|
if (codeLibraryName && (codeLibraryNameEnd
|
|
|
|
= strchr(codeLibraryName, system->pathSeparator())))
|
2014-04-09 12:02:48 +00:00
|
|
|
*codeLibraryNameEnd = 0;
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (not system->success(system->make(&localThread))
|
|
|
|
or not system->success(system->make(&stateLock))
|
|
|
|
or not system->success(system->make(&heapLock))
|
|
|
|
or not system->success(system->make(&classLock))
|
|
|
|
or not system->success(system->make(&referenceLock))
|
|
|
|
or not system->success(system->make(&shutdownLock))
|
|
|
|
or not system->success(system->load(&libraries, bootstrapPropertyDup))) {
|
2007-07-06 23:50:26 +00:00
|
|
|
system->abort();
|
|
|
|
}
|
2013-01-31 12:54:23 +00:00
|
|
|
|
|
|
|
System::Library* additionalLibrary = 0;
|
|
|
|
while (codeLibraryNameEnd && codeLibraryNameEnd + 1 < bootstrapPropertyEnd) {
|
|
|
|
codeLibraryName = codeLibraryNameEnd + 1;
|
|
|
|
codeLibraryNameEnd = strchr(codeLibraryName, system->pathSeparator());
|
|
|
|
if (codeLibraryNameEnd)
|
|
|
|
*codeLibraryNameEnd = 0;
|
|
|
|
|
|
|
|
if (!system->success(system->load(&additionalLibrary, codeLibraryName)))
|
|
|
|
system->abort();
|
|
|
|
libraries->setNext(additionalLibrary);
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (bootstrapPropertyDup)
|
2013-01-31 20:06:35 +00:00
|
|
|
free((void*)bootstrapPropertyDup);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void Machine::dispose()
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
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
|
|
|
}
|
|
|
|
|
2012-06-02 15:06:22 +00:00
|
|
|
if (bootimage) {
|
|
|
|
heap->free(bootimage, bootimageSize);
|
|
|
|
}
|
|
|
|
|
2011-08-06 00:06:29 +00:00
|
|
|
heap->free(arguments, sizeof(const char*) * argumentCount);
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
for (unsigned int i = 0; i < propertyCount; i++) {
|
2014-04-09 06:16:53 +00:00
|
|
|
heap->free(properties[i], sizeof(char) * (strlen(properties[i]) + 1));
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
Thread::Thread(Machine* m, GcThread* javaThread, Thread* parent)
|
|
|
|
: vtable(&(m->jniEnvVTable)),
|
|
|
|
m(m),
|
|
|
|
parent(parent),
|
|
|
|
peer(0),
|
|
|
|
child(0),
|
|
|
|
waitNext(0),
|
|
|
|
state(NoState),
|
|
|
|
criticalLevel(0),
|
|
|
|
systemThread(0),
|
|
|
|
lock(0),
|
|
|
|
javaThread(javaThread),
|
|
|
|
exception(0),
|
|
|
|
heapIndex(0),
|
|
|
|
heapOffset(0),
|
|
|
|
protector(0),
|
|
|
|
classInitStack(0),
|
|
|
|
libraryLoadStack(0),
|
|
|
|
runnable(this),
|
|
|
|
defaultHeap(
|
|
|
|
static_cast<uintptr_t*>(m->heap->allocate(ThreadHeapSizeInBytes))),
|
|
|
|
heap(defaultHeap),
|
|
|
|
backupHeapIndex(0),
|
|
|
|
flags(ActiveFlag)
|
2014-07-11 15:50:18 +00:00
|
|
|
{
|
|
|
|
}
|
2007-10-25 22:06:05 +00:00
|
|
|
|
2014-07-11 15:50:18 +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) {
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(this, m->rootThread == 0);
|
|
|
|
assertT(this, javaThread == 0);
|
2007-07-07 18:09:16 +00:00
|
|
|
|
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) {
|
2012-06-02 15:06:22 +00:00
|
|
|
bool lzma = strncmp("lzma:", imageFunctionName, 5) == 0;
|
2014-07-11 15:50:18 +00:00
|
|
|
const char* symbolName = lzma ? imageFunctionName + 5 : imageFunctionName;
|
2012-06-02 15:06:22 +00:00
|
|
|
|
|
|
|
void* imagep = m->libraries->resolve(symbolName);
|
2011-09-20 22:30:30 +00:00
|
|
|
if (imagep) {
|
2015-03-16 21:32:50 +00:00
|
|
|
uint8_t* (*imageFunction)(size_t*);
|
2011-09-20 22:30:30 +00:00
|
|
|
memcpy(&imageFunction, &imagep, BytesPerWord);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2015-03-16 21:32:50 +00:00
|
|
|
size_t size = 0;
|
2012-06-02 15:06:22 +00:00
|
|
|
uint8_t* imageBytes = imageFunction(&size);
|
|
|
|
if (lzma) {
|
|
|
|
#ifdef AVIAN_USE_LZMA
|
2014-07-11 15:50:18 +00:00
|
|
|
m->bootimage = image = reinterpret_cast<BootImage*>(decodeLZMA(
|
|
|
|
m->system, m->heap, imageBytes, size, &(m->bootimageSize)));
|
2012-06-02 15:06:22 +00:00
|
|
|
#else
|
|
|
|
abort(this);
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
image = reinterpret_cast<BootImage*>(imageBytes);
|
|
|
|
}
|
2011-09-20 22:30:30 +00:00
|
|
|
|
|
|
|
const char* codeFunctionName = findProperty(m, "avian.codeimage");
|
|
|
|
if (codeFunctionName) {
|
|
|
|
void* codep = m->libraries->resolve(codeFunctionName);
|
|
|
|
if (codep) {
|
2015-03-16 21:32:50 +00:00
|
|
|
uint8_t* (*codeFunction)(size_t*);
|
2011-09-20 22:30:30 +00:00
|
|
|
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);
|
2013-03-15 19:25:12 +00:00
|
|
|
makeArrayInterfaceTable(this);
|
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
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
GcWeakHashMap* map = makeWeakHashMap(this, 0, 0);
|
|
|
|
// sequence point, for gc (don't recombine statements)
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(this)->setByteArrayMap(this, map->as<GcHashMap>(this));
|
2014-06-30 01:44:41 +00:00
|
|
|
|
|
|
|
map = makeWeakHashMap(this, 0, 0);
|
|
|
|
// sequence point, for gc (don't recombine statements)
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(this)->setMonitorMap(this, map->as<GcHashMap>(this));
|
2014-06-30 01:44:41 +00:00
|
|
|
|
|
|
|
GcVector* v = makeVector(this, 0, 0);
|
|
|
|
// sequence point, for gc (don't recombine statements)
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(this)->setClassRuntimeDataTable(this, v);
|
2014-06-30 01:44:41 +00:00
|
|
|
|
|
|
|
v = makeVector(this, 0, 0);
|
|
|
|
// sequence point, for gc (don't recombine statements)
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(this)->setMethodRuntimeDataTable(this, v);
|
2014-06-30 01:44:41 +00:00
|
|
|
|
|
|
|
v = makeVector(this, 0, 0);
|
|
|
|
// sequence point, for gc (don't recombine statements)
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(this)->setJNIMethodTable(this, v);
|
2010-06-19 22:40:21 +00:00
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
v = makeVector(this, 0, 0);
|
|
|
|
// sequence point, for gc (don't recombine statements)
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(this)->setJNIFieldTable(this, v);
|
2010-06-19 22:40:21 +00:00
|
|
|
|
2007-09-10 23:33:58 +00:00
|
|
|
m->localThread->set(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
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void Thread::exit()
|
2007-07-07 18:09:16 +00:00
|
|
|
{
|
2014-07-11 15:50:18 +00:00
|
|
|
if (state != Thread::ExitState and state != Thread::ZombieState) {
|
2007-07-07 18:09:16 +00:00
|
|
|
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 {
|
2014-06-28 23:24:24 +00:00
|
|
|
javaThread->peer() = 0;
|
2010-11-16 17:50:19 +00:00
|
|
|
|
2012-02-04 00:20:20 +00:00
|
|
|
enter(this, Thread::ZombieState);
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void Thread::dispose()
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
2012-02-04 00:20:20 +00:00
|
|
|
if (lock) {
|
|
|
|
lock->dispose();
|
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
|
2012-02-04 00:20:20 +00:00
|
|
|
if (systemThread) {
|
|
|
|
systemThread->dispose();
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
--m->threadCount;
|
2012-02-03 19:00:02 +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
|
|
|
}
|
|
|
|
|
2017-11-21 17:06:18 +00:00
|
|
|
bool Thread::isBlacklisting()
|
|
|
|
{
|
|
|
|
return (javaThread != NULL) && javaThread->blacklisting();
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void 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
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
GcPair* hooks = roots(t)->shutdownHooks();
|
2009-08-19 20:27:03 +00:00
|
|
|
PROTECT(t, hooks);
|
2007-07-07 18:09:16 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(t)->setShutdownHooks(t, 0);
|
2007-07-17 01:55:49 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcPair* h = hooks;
|
2009-08-19 20:27:03 +00:00
|
|
|
PROTECT(t, h);
|
2014-06-29 05:48:17 +00:00
|
|
|
for (; h; h = cast<GcPair>(t, h->second())) {
|
|
|
|
startThread(t, cast<GcThread>(t, h->first()));
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
|
2009-08-19 20:27:03 +00:00
|
|
|
// wait for hooks to exit
|
|
|
|
h = hooks;
|
2014-06-29 05:48:17 +00:00
|
|
|
for (; h; h = cast<GcPair>(t, h->second())) {
|
2009-08-19 20:27:03 +00:00
|
|
|
while (true) {
|
2014-07-11 15:47:57 +00:00
|
|
|
Thread* ht
|
|
|
|
= reinterpret_cast<Thread*>(cast<GcThread>(t, h->first())->peer());
|
2007-07-17 01:55:49 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
{
|
|
|
|
ACQUIRE(t, t->m->stateLock);
|
2007-07-11 04:19:26 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (ht == 0 or ht->state == Thread::ZombieState
|
|
|
|
or ht->state == Thread::JoinedState) {
|
2009-08-19 20:27:03 +00:00
|
|
|
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
|
2014-07-11 15:50:18 +00:00
|
|
|
{
|
|
|
|
ACQUIRE(t, t->m->stateLock);
|
2009-08-24 23:51:31 +00:00
|
|
|
Thread* finalizeThread = t->m->finalizeThread;
|
|
|
|
if (finalizeThread) {
|
|
|
|
t->m->finalizeThread = 0;
|
|
|
|
t->m->stateLock->notifyAll(t->systemThread);
|
|
|
|
|
|
|
|
while (finalizeThread->state != Thread::ZombieState
|
2014-07-11 15:50:18 +00:00
|
|
|
and finalizeThread->state != Thread::JoinedState) {
|
2009-08-24 23:51:31 +00:00
|
|
|
ENTER(t, Thread::IdleState);
|
2014-07-11 15:50:18 +00:00
|
|
|
t->m->stateLock->wait(t->systemThread, 0);
|
2009-08-24 23:51:31 +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
|
|
|
|
|
|
|
// 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
|
2014-07-11 15:50:18 +00:00
|
|
|
{
|
|
|
|
ACQUIRE(t, t->m->stateLock);
|
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
|
|
|
|
|
|
|
t->m->alive = false;
|
|
|
|
|
|
|
|
visitAll(t, t->m->rootThread, interruptDaemon);
|
|
|
|
}
|
2007-07-07 18:09:16 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void enter(Thread* t, Thread::State s)
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
2007-07-16 01:03:02 +00:00
|
|
|
stress(t);
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (s == t->state)
|
|
|
|
return;
|
2007-07-06 23:50:26 +00:00
|
|
|
|
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
|
2014-07-11 15:50:18 +00:00
|
|
|
#define INCREMENT atomicIncrement
|
|
|
|
#define ACQUIRE_LOCK ACQUIRE_RAW(t, t->m->stateLock)
|
|
|
|
#define STORE_LOAD_MEMORY_BARRIER storeLoadMemoryBarrier()
|
2009-11-28 22:01:54 +00:00
|
|
|
#else
|
2014-07-11 15:50:18 +00:00
|
|
|
#define INCREMENT(pointer, value) *(pointer) += value;
|
|
|
|
#define ACQUIRE_LOCK
|
|
|
|
#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);
|
2014-07-11 15:50:18 +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) {
|
2014-07-11 15:50:18 +00:00
|
|
|
case Thread::ActiveState:
|
|
|
|
break;
|
2008-01-18 01:47:32 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
default:
|
|
|
|
abort(t);
|
2008-01-18 01:47:32 +00:00
|
|
|
}
|
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
t->state = Thread::ExclusiveState;
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->exclusive = t;
|
2014-07-11 15:50:18 +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
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, t->m->activeCount > 0);
|
2009-11-28 22:01:54 +00:00
|
|
|
INCREMENT(&(t->m->activeCount), -1);
|
|
|
|
|
|
|
|
t->state = s;
|
|
|
|
|
fix concurrency bugs on ios+arm64 in `enter`
At first, it might look like the atomicIncrement operations here,
since they resolve to OSAtomicCompareAndSwap32Barrier, ought to
provide all the memory barrier guarantees we need; however, it turns
out it's not quite sufficient.
Here's why: Apple's OSAtomic*Barrier operations guarantee that memory
operations *before* the atomic op won't be reordered with memory
operations *after* the atomic op - but makes no guarantee that the
atomic op itself won't be reordered with other operations before or
after it. The key is that the atomic operation is not really atomic,
but rather consists of separate read, check and write steps - in a
loop, no less. Here, presumably, the read of t->m->exclusive is
hoisted by the out-of-order processor to between the read and write
steps of the "atomic" increment of t->m->activeCount.
Longer term, it probably makes sense to replace this with the c11
<stdatomic.h> operations or the c++11 <atomic> types. We ought to
actually use the atomic increment operations provided there. As it
is, our atomicIncrement looks substantially less efficient than those,
since it's actually implemented on arm64 as two nested loops (one in
atomicIncrement and one in the compare-and-swap) instead of one. We
should also evaluate whether the various instances of atomic
operations actually need as strong of barriers as we're giving them.
FWIW, the gcc __sync_* builtins seem to have the same problem, at
least on arm64.
2015-05-07 18:32:10 +00:00
|
|
|
STORE_LOAD_MEMORY_BARRIER;
|
|
|
|
|
2009-11-28 22:01:54 +00:00
|
|
|
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
|
|
|
|
}
|
2017-09-06 09:48:26 +00:00
|
|
|
/* fallthrough */
|
2009-11-28 22:01:54 +00:00
|
|
|
|
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: {
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, t->m->exclusive == t);
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->exclusive = 0;
|
2007-07-06 23:50:26 +00:00
|
|
|
} break;
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case Thread::ActiveState:
|
|
|
|
break;
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
default:
|
|
|
|
abort(t);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(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) {
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, t->m->liveCount > 0);
|
2014-07-11 15:50:18 +00:00
|
|
|
--t->m->liveCount;
|
2009-08-19 20:27:03 +00:00
|
|
|
|
2014-08-20 15:49:00 +00:00
|
|
|
if (t->getFlags() & Thread::DaemonFlag) {
|
2014-07-11 15:50:18 +00:00
|
|
|
--t->m->daemonCount;
|
2009-08-19 20:27:03 +00:00
|
|
|
}
|
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;
|
|
|
|
|
fix concurrency bugs on ios+arm64 in `enter`
At first, it might look like the atomicIncrement operations here,
since they resolve to OSAtomicCompareAndSwap32Barrier, ought to
provide all the memory barrier guarantees we need; however, it turns
out it's not quite sufficient.
Here's why: Apple's OSAtomic*Barrier operations guarantee that memory
operations *before* the atomic op won't be reordered with memory
operations *after* the atomic op - but makes no guarantee that the
atomic op itself won't be reordered with other operations before or
after it. The key is that the atomic operation is not really atomic,
but rather consists of separate read, check and write steps - in a
loop, no less. Here, presumably, the read of t->m->exclusive is
hoisted by the out-of-order processor to between the read and write
steps of the "atomic" increment of t->m->activeCount.
Longer term, it probably makes sense to replace this with the c11
<stdatomic.h> operations or the c++11 <atomic> types. We ought to
actually use the atomic increment operations provided there. As it
is, our atomicIncrement looks substantially less efficient than those,
since it's actually implemented on arm64 as two nested loops (one in
atomicIncrement and one in the compare-and-swap) instead of one. We
should also evaluate whether the various instances of atomic
operations actually need as strong of barriers as we're giving them.
FWIW, the gcc __sync_* builtins seem to have the same problem, at
least on arm64.
2015-05-07 18:32:10 +00:00
|
|
|
STORE_LOAD_MEMORY_BARRIER;
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
{
|
|
|
|
ACQUIRE_LOCK;
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2009-11-28 22:01:54 +00:00
|
|
|
switch (t->state) {
|
|
|
|
case Thread::ExclusiveState: {
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(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) {
|
2014-07-11 15:50:18 +00:00
|
|
|
++t->m->liveCount;
|
|
|
|
++t->m->threadCount;
|
2009-11-28 22:01:54 +00:00
|
|
|
}
|
|
|
|
t->state = s;
|
|
|
|
} break;
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
default:
|
|
|
|
abort(t);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
}
|
|
|
|
break;
|
2007-07-06 23:50:26 +00:00
|
|
|
|
|
|
|
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: {
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, t->m->exclusive == t);
|
2013-02-22 23:33:07 +00:00
|
|
|
// exit state should also be exclusive, so don't set 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;
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
case Thread::ActiveState:
|
|
|
|
break;
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
default:
|
|
|
|
abort(t);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
2007-07-18 01:33:00 +00:00
|
|
|
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(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;
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
default:
|
|
|
|
abort(t);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
object allocate2(Thread* t, unsigned sizeInBytes, bool objectMask)
|
2008-01-10 01:20:36 +00:00
|
|
|
{
|
2014-07-11 15:50:18 +00:00
|
|
|
return allocate3(
|
|
|
|
t,
|
|
|
|
t->m->heap,
|
|
|
|
ceilingDivide(sizeInBytes, BytesPerWord) > ThreadHeapSizeInWords
|
|
|
|
? Machine::FixedAllocation
|
|
|
|
: Machine::MovableAllocation,
|
|
|
|
sizeInBytes,
|
|
|
|
objectMask);
|
2008-01-10 01:20:36 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
object allocate3(Thread* t,
|
2014-05-05 04:43:27 +00:00
|
|
|
Alloc* allocator,
|
2014-07-11 15:50:18 +00:00
|
|
|
Machine::AllocationType type,
|
|
|
|
unsigned sizeInBytes,
|
|
|
|
bool objectMask)
|
2007-10-28 01:54:30 +00:00
|
|
|
{
|
2013-02-05 16:48:20 +00:00
|
|
|
expect(t, t->criticalLevel == 0);
|
|
|
|
|
2014-08-20 15:49:00 +00:00
|
|
|
if (UNLIKELY(t->getFlags() & Thread::UseBackupHeapFlag)) {
|
2014-07-11 15:50:18 +00:00
|
|
|
expect(t,
|
|
|
|
t->backupHeapIndex + ceilingDivide(sizeInBytes, BytesPerWord)
|
2010-06-19 22:40:21 +00:00
|
|
|
<= ThreadBackupHeapSizeInWords);
|
2014-07-11 15:50:18 +00:00
|
|
|
|
2008-04-09 19:08:13 +00:00
|
|
|
object o = reinterpret_cast<object>(t->backupHeap + t->backupHeapIndex);
|
2013-02-11 01:06:15 +00:00
|
|
|
t->backupHeapIndex += ceilingDivide(sizeInBytes, BytesPerWord);
|
2013-02-11 00:38:51 +00:00
|
|
|
fieldAtOffset<object>(o, 0) = 0;
|
2008-04-09 19:08:13 +00:00
|
|
|
return o;
|
2014-08-20 15:49:00 +00:00
|
|
|
} else if (UNLIKELY(t->getFlags() & Thread::TracingFlag)) {
|
2014-07-11 15:50:18 +00:00
|
|
|
expect(t,
|
|
|
|
t->heapIndex + ceilingDivide(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
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
|
2009-07-18 01:37:46 +00:00
|
|
|
do {
|
|
|
|
switch (type) {
|
|
|
|
case Machine::MovableAllocation:
|
2013-02-11 01:06:15 +00:00
|
|
|
if (t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord)
|
2014-07-11 15:50:18 +00:00
|
|
|
> ThreadHeapSizeInWords) {
|
2009-07-18 01:37:46 +00:00
|
|
|
t->heap = 0;
|
2010-12-27 22:55:23 +00:00
|
|
|
if ((not t->m->heap->limitExceeded())
|
2014-07-11 15:50:18 +00:00
|
|
|
and t->m->heapPoolIndex < ThreadHeapPoolSize) {
|
|
|
|
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:
|
2014-07-11 15:50:18 +00:00
|
|
|
if (t->m->fixedFootprint + sizeInBytes > FixedFootprintThresholdInBytes) {
|
2009-07-18 01:37:46 +00:00
|
|
|
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
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
int pendingAllocation = t->m->heap->fixedFootprint(
|
|
|
|
ceilingDivide(sizeInBytes, BytesPerWord), objectMask);
|
2013-03-08 03:17:05 +00:00
|
|
|
|
|
|
|
if (t->heap == 0 or t->m->heap->limitExceeded(pendingAllocation)) {
|
2009-07-18 01:37:46 +00:00
|
|
|
// fprintf(stderr, "gc");
|
|
|
|
// vmPrintTrace(t);
|
2013-03-08 03:17:05 +00:00
|
|
|
collect(t, Heap::MinorCollection, pendingAllocation);
|
2009-07-18 01:37:46 +00:00
|
|
|
}
|
2010-12-27 22:55:23 +00:00
|
|
|
|
2013-03-08 03:17:05 +00:00
|
|
|
if (t->m->heap->limitExceeded(pendingAllocation)) {
|
2014-06-30 01:44:41 +00:00
|
|
|
throw_(t, roots(t)->outOfMemoryError());
|
2010-12-27 22:55:23 +00:00
|
|
|
}
|
2009-07-18 01:37:46 +00:00
|
|
|
} while (type == Machine::MovableAllocation
|
2013-02-11 01:06:15 +00:00
|
|
|
and t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord)
|
2014-07-11 15:50:18 +00:00
|
|
|
> ThreadHeapSizeInWords);
|
2013-02-03 22:53:36 +00:00
|
|
|
|
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: {
|
2014-07-11 15:50:18 +00:00
|
|
|
object o = static_cast<object>(t->m->heap->allocateFixed(
|
|
|
|
allocator, ceilingDivide(sizeInBytes, BytesPerWord), objectMask));
|
2007-10-28 19:14:53 +00:00
|
|
|
|
2013-03-08 03:17:05 +00:00
|
|
|
memset(o, 0, sizeInBytes);
|
2007-10-28 19:14:53 +00:00
|
|
|
|
2013-03-08 03:17:05 +00:00
|
|
|
alias(o, 0) = FixedMark;
|
2014-07-11 15:50:18 +00:00
|
|
|
|
|
|
|
t->m->fixedFootprint += t->m->heap->fixedFootprint(
|
|
|
|
ceilingDivide(sizeInBytes, BytesPerWord), objectMask);
|
|
|
|
|
2013-03-08 03:17:05 +00:00
|
|
|
return o;
|
2008-01-10 01:20:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
case Machine::ImmortalAllocation: {
|
2014-07-11 15:50:18 +00:00
|
|
|
object o = static_cast<object>(t->m->heap->allocateImmortalFixed(
|
|
|
|
allocator, ceilingDivide(sizeInBytes, BytesPerWord), objectMask));
|
2008-01-10 01:20:36 +00:00
|
|
|
|
2013-03-08 03:17:05 +00:00
|
|
|
memset(o, 0, sizeInBytes);
|
2009-03-04 03:05:48 +00:00
|
|
|
|
2013-03-08 03:17:05 +00:00
|
|
|
alias(o, 0) = FixedMark;
|
2008-01-10 01:20:36 +00:00
|
|
|
|
2013-03-08 03:17:05 +00:00
|
|
|
return o;
|
2008-01-10 01:20:36 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
default:
|
|
|
|
abort(t);
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void collect(Thread* t, Heap::CollectionType type, int pendingAllocation)
|
2013-03-08 03:17:05 +00:00
|
|
|
{
|
|
|
|
ENTER(t, Thread::ExclusiveState);
|
|
|
|
|
|
|
|
unsigned pending = pendingAllocation
|
2014-07-11 15:50:18 +00:00
|
|
|
- (t->m->heapPoolIndex * ThreadHeapSizeInWords);
|
2013-03-08 03:17:05 +00:00
|
|
|
|
|
|
|
if (t->m->heap->limitExceeded(pending)) {
|
|
|
|
type = Heap::MajorCollection;
|
|
|
|
}
|
|
|
|
|
|
|
|
doCollect(t, type, pendingAllocation);
|
|
|
|
|
|
|
|
if (t->m->heap->limitExceeded(pending)) {
|
|
|
|
// try once more, giving the heap a chance to squeeze everything
|
|
|
|
// into the smallest possible space:
|
|
|
|
doCollect(t, Heap::MajorCollection, pendingAllocation);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
object makeNewGeneral(Thread* t, GcClass* class_)
|
2009-07-22 00:57:55 +00:00
|
|
|
{
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, t->state == Thread::ActiveState);
|
2009-07-22 00:57:55 +00:00
|
|
|
|
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);
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (class_->vmFlags() & WeakReferenceFlag) {
|
2009-07-22 00:57:55 +00:00
|
|
|
ACQUIRE(t, t->m->referenceLock);
|
2014-06-29 05:48:17 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
cast<GcJreference>(t, instance)->vmNext() = t->m->weakReferences;
|
2014-06-28 23:24:24 +00:00
|
|
|
t->m->weakReferences = cast<GcJreference>(t, instance);
|
2009-07-22 00:57:55 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (class_->vmFlags() & HasFinalizerFlag) {
|
2009-08-24 23:51:31 +00:00
|
|
|
addFinalizer(t, instance, 0);
|
2009-07-22 00:57:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +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
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcByteArray* makeByteArrayV(Thread* t, const char* format, va_list a, int size)
|
2010-12-27 22:55:23 +00:00
|
|
|
{
|
2012-02-29 18:49:13 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, buffer, size);
|
2014-07-11 15:50:18 +00:00
|
|
|
|
2012-02-29 18:49:13 +00:00
|
|
|
int r = vm::vsnprintf(RUNTIME_ARRAY_BODY(buffer), size - 1, format, a);
|
|
|
|
if (r >= 0 and r < size - 1) {
|
2014-06-28 23:24:24 +00:00
|
|
|
GcByteArray* s = makeByteArray(t, strlen(RUNTIME_ARRAY_BODY(buffer)) + 1);
|
2014-07-11 15:47:57 +00:00
|
|
|
memcpy(s->body().begin(), RUNTIME_ARRAY_BODY(buffer), s->length());
|
2012-02-29 18:49:13 +00:00
|
|
|
return s;
|
|
|
|
} else {
|
|
|
|
return 0;
|
2011-07-10 00:00:19 +00:00
|
|
|
}
|
2010-12-27 22:55:23 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcByteArray* makeByteArray(Thread* t, const char* format, ...)
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
2012-02-29 18:49:13 +00:00
|
|
|
int size = 256;
|
|
|
|
while (true) {
|
|
|
|
va_list a;
|
|
|
|
va_start(a, format);
|
2014-06-28 23:24:24 +00:00
|
|
|
GcByteArray* s = makeByteArrayV(t, format, a, size);
|
2012-02-29 18:49:13 +00:00
|
|
|
va_end(a);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2012-02-29 18:49:13 +00:00
|
|
|
if (s) {
|
|
|
|
return s;
|
|
|
|
} else {
|
|
|
|
size *= 2;
|
|
|
|
}
|
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcString* makeString(Thread* t, const char* format, ...)
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
2012-02-29 18:49:13 +00:00
|
|
|
int size = 256;
|
|
|
|
while (true) {
|
|
|
|
va_list a;
|
|
|
|
va_start(a, format);
|
2014-06-28 23:24:24 +00:00
|
|
|
GcByteArray* s = makeByteArrayV(t, format, a, size);
|
2012-02-29 18:49:13 +00:00
|
|
|
va_end(a);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2012-02-29 18:49:13 +00:00
|
|
|
if (s) {
|
2014-07-02 21:11:27 +00:00
|
|
|
return t->m->classpath->makeString(t, s, 0, s->length() - 1);
|
2012-02-29 18:49:13 +00:00
|
|
|
} else {
|
|
|
|
size *= 2;
|
|
|
|
}
|
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
int stringUTFLength(Thread* t,
|
|
|
|
GcString* string,
|
|
|
|
unsigned start,
|
|
|
|
unsigned length)
|
2010-09-10 21:05:29 +00:00
|
|
|
{
|
|
|
|
unsigned result = 0;
|
2010-04-20 16:03:07 +00:00
|
|
|
|
2010-09-10 21:05:29 +00:00
|
|
|
if (length) {
|
2014-07-02 21:11:27 +00:00
|
|
|
object data = string->data();
|
2014-05-29 04:17:25 +00:00
|
|
|
if (objectClass(t, data) == type(t, GcByteArray::Type)) {
|
2010-09-10 21:05:29 +00:00
|
|
|
result = length;
|
2010-04-20 16:03:07 +00:00
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcCharArray* a = cast<GcCharArray>(t, data);
|
2010-09-10 21:05:29 +00:00
|
|
|
for (unsigned i = 0; i < length; ++i) {
|
2014-06-29 05:48:17 +00:00
|
|
|
uint16_t c = a->body()[string->offset(t) + start + i];
|
2014-07-11 15:50:18 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void stringChars(Thread* t,
|
|
|
|
GcString* 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) {
|
2014-07-02 21:11:27 +00:00
|
|
|
object data = string->data();
|
2014-05-29 04:17:25 +00:00
|
|
|
if (objectClass(t, data) == type(t, GcByteArray::Type)) {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* b = cast<GcByteArray>(t, data);
|
2014-07-11 15:47:57 +00:00
|
|
|
memcpy(chars, &b->body()[string->offset(t) + start], length);
|
2009-08-13 15:17:05 +00:00
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcCharArray* c = cast<GcCharArray>(t, data);
|
2010-09-10 21:05:29 +00:00
|
|
|
for (unsigned i = 0; i < length; ++i) {
|
2014-06-29 05:48:17 +00:00
|
|
|
chars[i] = c->body()[string->offset(t) + 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
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void stringChars(Thread* t,
|
|
|
|
GcString* 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) {
|
2014-07-02 21:11:27 +00:00
|
|
|
object data = string->data();
|
2014-05-29 04:17:25 +00:00
|
|
|
if (objectClass(t, data) == type(t, GcByteArray::Type)) {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* b = cast<GcByteArray>(t, data);
|
2010-09-10 21:05:29 +00:00
|
|
|
for (unsigned i = 0; i < length; ++i) {
|
2014-06-29 05:48:17 +00:00
|
|
|
chars[i] = b->body()[string->offset(t) + start + i];
|
2009-08-13 15:17:05 +00:00
|
|
|
}
|
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcCharArray* c = cast<GcCharArray>(t, data);
|
2009-08-13 15:17:05 +00:00
|
|
|
memcpy(chars,
|
2014-06-29 05:48:17 +00:00
|
|
|
&c->body()[string->offset(t) + start],
|
2010-09-10 21:05:29 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void stringUTFChars(Thread* t,
|
|
|
|
GcString* string,
|
|
|
|
unsigned start,
|
|
|
|
unsigned length,
|
|
|
|
char* chars,
|
|
|
|
unsigned charsLength UNUSED)
|
2010-04-20 16:03:07 +00:00
|
|
|
{
|
2014-07-11 15:47:57 +00:00
|
|
|
assertT(t,
|
|
|
|
static_cast<unsigned>(stringUTFLength(t, string, start, length))
|
|
|
|
== charsLength);
|
2010-04-20 16:03:07 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
object data = string->data();
|
2014-06-29 05:48:17 +00:00
|
|
|
if (objectClass(t, data) == type(t, GcByteArray::Type)) {
|
|
|
|
GcByteArray* b = cast<GcByteArray>(t, data);
|
2014-07-11 15:47:57 +00:00
|
|
|
memcpy(chars, &b->body()[string->offset(t) + start], length);
|
2014-06-29 05:48:17 +00:00
|
|
|
chars[length] = 0;
|
2012-08-04 18:36:18 +00:00
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcCharArray* cs = cast<GcCharArray>(t, data);
|
2012-08-04 18:36:18 +00:00
|
|
|
int j = 0;
|
|
|
|
for (unsigned i = 0; i < length; ++i) {
|
2014-06-29 05:48:17 +00:00
|
|
|
uint16_t c = cs->body()[string->offset(t) + start + i];
|
2014-07-11 15:50:18 +00:00
|
|
|
if (!c) { // null char
|
2012-08-04 18:36:18 +00:00
|
|
|
chars[j++] = 0;
|
|
|
|
} else if (c < 0x80) { // ASCII char
|
|
|
|
chars[j++] = static_cast<char>(c);
|
2014-07-11 15:50:18 +00:00
|
|
|
} else if (c < 0x800) { // two-byte char
|
2012-08-04 18:36:18 +00:00
|
|
|
chars[j++] = static_cast<char>(0x0c0 | (c >> 6));
|
|
|
|
chars[j++] = static_cast<char>(0x080 | (c & 0x03f));
|
2014-07-11 15:50:18 +00:00
|
|
|
} else { // three-byte char
|
2012-08-04 18:36:18 +00:00
|
|
|
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));
|
2010-04-20 16:03:07 +00:00
|
|
|
}
|
2012-08-04 18:36:18 +00:00
|
|
|
}
|
|
|
|
chars[j] = 0;
|
2014-06-29 05:48:17 +00:00
|
|
|
}
|
2010-04-20 16:03:07 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
uint64_t resolveBootstrap(Thread* t, uintptr_t* arguments)
|
2010-12-27 22:55:23 +00:00
|
|
|
{
|
2014-07-11 15:47:57 +00:00
|
|
|
GcByteArray* name
|
|
|
|
= cast<GcByteArray>(t, reinterpret_cast<object>(arguments[0]));
|
2010-12-27 22:55:23 +00:00
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
resolveSystemClass(t, roots(t)->bootLoader(), name);
|
2010-12-27 22:55:23 +00:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
bool isAssignableFrom(Thread* t, GcClass* a, GcClass* b)
|
2007-07-24 01:44:20 +00:00
|
|
|
{
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, a);
|
|
|
|
assertT(t, b);
|
2010-09-14 16:49:41 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (a == b)
|
|
|
|
return true;
|
2007-11-05 14:28:46 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (a->flags() & ACC_INTERFACE) {
|
|
|
|
if (b->vmFlags() & BootstrapFlag) {
|
2014-07-11 15:47:57 +00:00
|
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(b->name())};
|
2010-12-27 22:55:23 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* itable = cast<GcArray>(t, b->interfaceTable());
|
2011-04-10 03:09:59 +00:00
|
|
|
if (itable) {
|
2014-05-29 04:17:25 +00:00
|
|
|
unsigned stride = (b->flags() & ACC_INTERFACE) ? 1 : 2;
|
2014-06-29 05:48:17 +00:00
|
|
|
for (unsigned i = 0; i < itable->length(); i += stride) {
|
2014-07-02 21:11:27 +00:00
|
|
|
if (itable->body()[i] == a) {
|
2011-04-10 03:09:59 +00:00
|
|
|
return true;
|
2007-07-24 01:44:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-29 04:17:25 +00:00
|
|
|
} else if (a->arrayDimensions()) {
|
|
|
|
if (b->arrayDimensions()) {
|
2014-07-11 15:47:57 +00:00
|
|
|
return isAssignableFrom(
|
|
|
|
t, a->arrayElementClass(), b->arrayElementClass());
|
2007-08-20 02:57:32 +00:00
|
|
|
}
|
2014-07-11 15:47:57 +00:00
|
|
|
} else if ((a->vmFlags() & PrimitiveFlag) == (b->vmFlags() & PrimitiveFlag)) {
|
2014-06-21 04:16:33 +00:00
|
|
|
for (; b; b = b->super()) {
|
2007-07-24 01:44:20 +00:00
|
|
|
if (b == a) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
bool instanceOf(Thread* t, GcClass* class_, object o)
|
2007-07-24 01:44:20 +00:00
|
|
|
{
|
|
|
|
if (o == 0) {
|
|
|
|
return false;
|
2007-07-24 03:16:59 +00:00
|
|
|
} else {
|
2014-06-21 04:16:33 +00:00
|
|
|
return isAssignableFrom(t, class_, objectClass(t, o));
|
2007-07-24 01:44:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcMethod* classInitializer(Thread* t, GcClass* class_)
|
2007-07-28 16:10:13 +00:00
|
|
|
{
|
2014-06-29 05:48:17 +00:00
|
|
|
if (GcArray* mtable = cast<GcArray>(t, class_->methodTable())) {
|
|
|
|
PROTECT(t, mtable);
|
2014-07-11 15:47:57 +00:00
|
|
|
for (unsigned i = 0; i < mtable->length(); ++i) {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcMethod* o = cast<GcMethod>(t, mtable->body()[i]);
|
2011-07-18 01:51:48 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
if (o->vmFlags() & ClassInitFlag) {
|
2011-07-18 01:51:48 +00:00
|
|
|
return o;
|
2014-06-28 23:24:24 +00:00
|
|
|
}
|
2011-07-18 01:51:48 +00:00
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +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
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
default:
|
|
|
|
abort(t);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
unsigned fieldType(Thread* t, unsigned code)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
default:
|
|
|
|
abort(t);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +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
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
default:
|
|
|
|
abort(t);
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
2007-07-11 04:19:26 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* parseClass(Thread* t,
|
|
|
|
GcClassLoader* loader,
|
|
|
|
const uint8_t* data,
|
|
|
|
unsigned size,
|
|
|
|
Gc::Type throwType)
|
2007-07-30 23:19:05 +00:00
|
|
|
{
|
2009-08-10 13:56:16 +00:00
|
|
|
PROTECT(t, loader);
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
class Client : public Stream::Client {
|
2007-07-30 23:19:05 +00:00
|
|
|
public:
|
2014-07-11 15:50:18 +00:00
|
|
|
Client(Thread* t) : t(t)
|
|
|
|
{
|
|
|
|
}
|
2007-07-30 23:19:05 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
virtual void NO_RETURN handleError()
|
|
|
|
{
|
2013-02-12 01:51:39 +00:00
|
|
|
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);
|
2014-07-11 15:50:18 +00:00
|
|
|
unsigned minorVer = s.read2(); // minor version
|
|
|
|
unsigned majorVer = s.read2(); // major version
|
|
|
|
if (DebugClassReader) {
|
2012-05-22 19:53:32 +00:00
|
|
|
fprintf(stderr, "read class (minor %d major %d)\n", minorVer, majorVer);
|
|
|
|
}
|
2007-07-30 23:19:05 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcSingleton* pool = parsePool(t, s);
|
2007-07-30 23:19:05 +00:00
|
|
|
PROTECT(t, pool);
|
|
|
|
|
|
|
|
unsigned flags = s.read2();
|
|
|
|
unsigned name = s.read2();
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* class_ = (GcClass*)makeClass(
|
|
|
|
t,
|
|
|
|
flags,
|
|
|
|
0, // VM flags
|
|
|
|
0, // fixed size
|
|
|
|
0, // array size
|
|
|
|
0, // array dimensions
|
|
|
|
0, // array element class
|
|
|
|
0, // runtime data index
|
|
|
|
0, // object mask
|
|
|
|
cast<GcReference>(t, singletonObject(t, pool, name - 1))->name(),
|
|
|
|
0, // source file
|
|
|
|
0, // super
|
|
|
|
0, // interfaces
|
|
|
|
0, // vtable
|
|
|
|
0, // fields
|
|
|
|
0, // methods
|
|
|
|
0, // addendum
|
|
|
|
0, // static table
|
|
|
|
loader,
|
|
|
|
0, // source
|
|
|
|
0); // vtable length
|
2007-07-30 23:19:05 +00:00
|
|
|
PROTECT(t, class_);
|
2014-07-11 15:50:18 +00:00
|
|
|
|
2007-07-30 23:19:05 +00:00
|
|
|
unsigned super = s.read2();
|
|
|
|
if (super) {
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* sc = resolveClass(
|
|
|
|
t,
|
|
|
|
loader,
|
|
|
|
cast<GcReference>(t, singletonObject(t, pool, super - 1))->name(),
|
|
|
|
true,
|
|
|
|
throwType);
|
2007-07-30 23:19:05 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
class_->setSuper(t, sc);
|
2007-07-30 23:19:05 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
class_->vmFlags() |= (sc->vmFlags() & (ReferenceFlag | WeakReferenceFlag
|
|
|
|
| HasFinalizerFlag | NeedInitFlag));
|
2007-07-30 23:19:05 +00:00
|
|
|
}
|
2012-05-22 19:53:32 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
if (DebugClassReader) {
|
2012-05-22 19:53:32 +00:00
|
|
|
fprintf(stderr, " flags %d name %d super %d\n", flags, name, super);
|
|
|
|
}
|
2014-07-11 15:50:18 +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);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcArray* vtable = cast<GcArray>(t, class_->virtualTable());
|
|
|
|
unsigned vtableLength = (vtable ? vtable->length() : 0);
|
2007-11-05 21:40:17 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* real = t->m->processor->makeClass(t,
|
|
|
|
class_->flags(),
|
|
|
|
class_->vmFlags(),
|
|
|
|
class_->fixedSize(),
|
|
|
|
class_->arrayElementSize(),
|
|
|
|
class_->arrayDimensions(),
|
|
|
|
class_->arrayElementClass(),
|
|
|
|
class_->objectMask(),
|
|
|
|
class_->name(),
|
|
|
|
class_->sourceFile(),
|
|
|
|
class_->super(),
|
|
|
|
class_->interfaceTable(),
|
|
|
|
class_->virtualTable(),
|
|
|
|
class_->fieldTable(),
|
|
|
|
class_->methodTable(),
|
|
|
|
class_->addendum(),
|
|
|
|
class_->staticTable(),
|
|
|
|
class_->loader(),
|
|
|
|
vtableLength);
|
2007-11-05 21:40:17 +00:00
|
|
|
|
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_);
|
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
if (roots(t)->poolMap()) {
|
2014-07-11 15:47:57 +00:00
|
|
|
object bootstrapClass = hashMapFind(t,
|
|
|
|
roots(t)->bootstrapClassMap(),
|
|
|
|
class_->name(),
|
|
|
|
byteArrayHash,
|
|
|
|
byteArrayEqual);
|
2011-08-30 01:00:17 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
hashMapInsert(t,
|
|
|
|
roots(t)->poolMap(),
|
|
|
|
bootstrapClass ? bootstrapClass : real,
|
|
|
|
pool,
|
|
|
|
objectHash);
|
2011-08-30 01:00:17 +00:00
|
|
|
}
|
|
|
|
|
2007-11-05 21:40:17 +00:00
|
|
|
return real;
|
2007-07-30 23:19:05 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
uint64_t runParseClass(Thread* t, uintptr_t* arguments)
|
2012-08-30 00:34:51 +00:00
|
|
|
{
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClassLoader* loader
|
|
|
|
= cast<GcClassLoader>(t, reinterpret_cast<object>(arguments[0]));
|
2012-08-30 00:34:51 +00:00
|
|
|
System::Region* region = reinterpret_cast<System::Region*>(arguments[1]);
|
2014-05-29 04:17:25 +00:00
|
|
|
Gc::Type throwType = static_cast<Gc::Type>(arguments[2]);
|
2012-08-30 00:34:51 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
return reinterpret_cast<uintptr_t>(
|
|
|
|
parseClass(t, loader, region->start(), region->length(), throwType));
|
2012-08-30 00:34:51 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* resolveSystemClass(Thread* t,
|
|
|
|
GcClassLoader* loader,
|
|
|
|
GcByteArray* spec,
|
|
|
|
bool throw_,
|
|
|
|
Gc::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
|
|
|
|
2017-11-21 17:06:18 +00:00
|
|
|
/*
|
|
|
|
* We require that SystemClassLoader.isForbidden() has already
|
|
|
|
* been executed once before isBlacklisting is set to true.
|
|
|
|
* Otherwise this code-block recurses until the stack explodes.
|
|
|
|
*/
|
|
|
|
if (t->isBlacklisting()
|
|
|
|
&& ::strcmp("avian/SystemClassLoader", reinterpret_cast<const char*>(spec->body().begin()))) {
|
|
|
|
GcMethod* forbid = resolveMethod(t,
|
|
|
|
roots(t)->bootLoader(),
|
|
|
|
"avian/SystemClassLoader",
|
|
|
|
"isForbidden",
|
|
|
|
"(Ljava/lang/String;)Z");
|
|
|
|
GcString *name = t->m->classpath->makeString(t, spec, 0, spec->length());
|
|
|
|
GcInt *result = cast<GcInt>(t, t->m->processor->invoke(t, forbid, NULL, name));
|
|
|
|
if (UNLIKELY(t->exception)) {
|
|
|
|
if (throw_) {
|
|
|
|
GcThrowable* e = t->exception;
|
|
|
|
t->exception = 0;
|
|
|
|
vm::throw_(t, e);
|
|
|
|
} else {
|
|
|
|
t->exception = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (result->value() == JNI_TRUE) {
|
|
|
|
if (throw_) {
|
|
|
|
throwNew(t, throwType, "%s", spec->body().begin());
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-30 10:03:22 +00:00
|
|
|
GcClass* class_ = findLoadedClass(t, loader, spec);
|
2007-07-14 17:31:01 +00:00
|
|
|
if (class_ == 0) {
|
2011-04-01 01:16:57 +00:00
|
|
|
PROTECT(t, class_);
|
|
|
|
|
2014-06-28 21:11:31 +00:00
|
|
|
if (loader->parent()) {
|
2014-07-11 15:47:57 +00:00
|
|
|
class_ = resolveSystemClass(t, loader->parent(), spec, false);
|
2010-09-14 16:49:41 +00:00
|
|
|
if (class_) {
|
|
|
|
return class_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
if (spec->body()[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 {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcSystemClassLoader* sysLoader = loader->as<GcSystemClassLoader>(t);
|
|
|
|
PROTECT(t, sysLoader);
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, file, spec->length() + 6);
|
2014-07-11 15:47:57 +00:00
|
|
|
memcpy(
|
|
|
|
RUNTIME_ARRAY_BODY(file), spec->body().begin(), spec->length() - 1);
|
|
|
|
memcpy(RUNTIME_ARRAY_BODY(file) + spec->length() - 1, ".class", 7);
|
2007-08-10 23:45:47 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
System::Region* region = static_cast<Finder*>(sysLoader->finder())
|
|
|
|
->find(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) {
|
2014-06-28 23:24:24 +00:00
|
|
|
fprintf(stderr, "parsing %s\n", spec->body().begin());
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
{
|
|
|
|
THREAD_RESOURCE(t, System::Region*, region, region->dispose());
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(loader),
|
|
|
|
reinterpret_cast<uintptr_t>(region),
|
|
|
|
static_cast<uintptr_t>(throwType)};
|
2012-08-30 00:34:51 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
// parse class file
|
2014-07-11 15:47:57 +00:00
|
|
|
class_ = cast<GcClass>(
|
|
|
|
t, reinterpret_cast<object>(runRaw(t, runParseClass, arguments)));
|
2012-08-30 00:34:51 +00:00
|
|
|
|
|
|
|
if (UNLIKELY(t->exception)) {
|
|
|
|
if (throw_) {
|
2014-06-28 23:24:24 +00:00
|
|
|
GcThrowable* e = t->exception;
|
2012-08-30 00:34:51 +00:00
|
|
|
t->exception = 0;
|
|
|
|
vm::throw_(t, e);
|
|
|
|
} else {
|
|
|
|
t->exception = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2010-12-27 22:55:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Verbose) {
|
2014-07-11 15:47:57 +00:00
|
|
|
fprintf(
|
|
|
|
stderr, "done parsing %s: %p\n", spec->body().begin(), class_);
|
2010-12-27 22:55:23 +00:00
|
|
|
}
|
2007-07-14 17:31:01 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
{
|
|
|
|
const char* source = static_cast<Finder*>(sysLoader->finder())
|
|
|
|
->sourceUrl(RUNTIME_ARRAY_BODY(file));
|
|
|
|
|
2011-04-01 01:16:57 +00:00
|
|
|
if (source) {
|
|
|
|
unsigned length = strlen(source);
|
2014-06-29 05:48:17 +00:00
|
|
|
GcByteArray* array = makeByteArray(t, length + 1);
|
|
|
|
memcpy(array->body().begin(), source, length);
|
2011-04-01 01:16:57 +00:00
|
|
|
array = internByteArray(t, array);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
class_->setSource(t, array);
|
2011-04-01 01:16:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* bootstrapClass
|
|
|
|
= cast<GcClass>(t,
|
|
|
|
hashMapFind(t,
|
|
|
|
roots(t)->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);
|
2014-07-11 15:50:18 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
updateBootstrapClass(t, bootstrapClass, class_);
|
|
|
|
class_ = bootstrapClass;
|
2007-07-14 17:31:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (class_) {
|
2014-07-11 15:47:57 +00:00
|
|
|
hashMapInsert(
|
|
|
|
t, cast<GcHashMap>(t, loader->map()), spec, class_, byteArrayHash);
|
2012-09-24 23:43:34 +00:00
|
|
|
|
2014-03-19 17:21:26 +00:00
|
|
|
updatePackageMap(t, class_);
|
2010-12-27 22:55:23 +00:00
|
|
|
} else if (throw_) {
|
2014-06-28 23:24:24 +00:00
|
|
|
throwNew(t, throwType, "%s", spec->body().begin());
|
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_;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* findLoadedClass(Thread* t, GcClassLoader* loader, GcByteArray* spec)
|
2010-09-14 16:49:41 +00:00
|
|
|
{
|
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);
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
return loader->map()
|
|
|
|
? cast<GcClass>(t,
|
|
|
|
hashMapFind(t,
|
|
|
|
cast<GcHashMap>(t, loader->map()),
|
|
|
|
spec,
|
|
|
|
byteArrayHash,
|
|
|
|
byteArrayEqual))
|
|
|
|
: 0;
|
2010-09-14 16:49:41 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* resolveClass(Thread* t,
|
|
|
|
GcClassLoader* loader,
|
|
|
|
GcByteArray* spec,
|
|
|
|
bool throw_,
|
|
|
|
Gc::Type throwType)
|
2009-08-10 13:56:16 +00:00
|
|
|
{
|
2014-05-29 04:17:25 +00:00
|
|
|
if (objectClass(t, loader) == type(t, GcSystemClassLoader::Type)) {
|
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);
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* c = findLoadedClass(t, loader, spec);
|
2010-12-01 03:27:36 +00:00
|
|
|
if (c) {
|
|
|
|
return c;
|
2010-09-17 01:43:27 +00:00
|
|
|
}
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
if (spec->body()[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 {
|
2014-06-30 01:44:41 +00:00
|
|
|
if (roots(t)->loadClassMethod() == 0) {
|
2014-07-11 15:47:57 +00:00
|
|
|
GcMethod* m = resolveMethod(t,
|
|
|
|
roots(t)->bootLoader(),
|
|
|
|
"java/lang/ClassLoader",
|
|
|
|
"loadClass",
|
|
|
|
"(Ljava/lang/String;)Ljava/lang/Class;");
|
2010-09-17 01:43:27 +00:00
|
|
|
|
|
|
|
if (m) {
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(t)->setLoadClassMethod(t, m);
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* classLoaderClass = type(t, GcClassLoader::Type);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (classLoaderClass->vmFlags() & BootstrapFlag) {
|
2014-07-11 15:47:57 +00:00
|
|
|
resolveSystemClass(
|
|
|
|
t, roots(t)->bootLoader(), classLoaderClass->name());
|
2010-09-17 01:43:27 +00:00
|
|
|
}
|
2014-07-11 15:50:18 +00:00
|
|
|
}
|
2010-09-17 01:43:27 +00:00
|
|
|
}
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcMethod* method = findVirtualMethod(
|
|
|
|
t, roots(t)->loadClassMethod(), objectClass(t, loader));
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
PROTECT(t, method);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, s, spec->length());
|
2014-07-11 15:47:57 +00:00
|
|
|
replace('/',
|
|
|
|
'.',
|
|
|
|
RUNTIME_ARRAY_BODY(s),
|
|
|
|
reinterpret_cast<char*>(spec->body().begin()));
|
2009-08-10 13:56:16 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
GcString* 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
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
uintptr_t arguments[] = {reinterpret_cast<uintptr_t>(method),
|
|
|
|
reinterpret_cast<uintptr_t>(loader),
|
|
|
|
reinterpret_cast<uintptr_t>(specString)};
|
2011-03-15 23:52:02 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcJclass* jc = cast<GcJclass>(
|
|
|
|
t, reinterpret_cast<object>(runRaw(t, invokeLoadClass, arguments)));
|
2011-03-15 23:52:02 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
if (LIKELY(jc)) {
|
2014-06-29 05:48:17 +00:00
|
|
|
c = jc->vmClass();
|
2011-03-15 23:52:02 +00:00
|
|
|
} else if (t->exception) {
|
|
|
|
if (throw_) {
|
2014-07-11 15:47:57 +00:00
|
|
|
GcThrowable* 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_) {
|
2014-06-28 23:24:24 +00:00
|
|
|
throwNew(t, throwType, "%s", spec->body().begin());
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcMethod* resolveMethod(Thread* t,
|
|
|
|
GcClass* class_,
|
|
|
|
const char* methodName,
|
|
|
|
const char* methodSpec)
|
2007-09-24 01:39:03 +00:00
|
|
|
{
|
2009-06-11 00:15:00 +00:00
|
|
|
PROTECT(t, class_);
|
2007-09-24 01:39:03 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
GcByteArray* name = makeByteArray(t, methodName);
|
2009-06-11 00:15:00 +00:00
|
|
|
PROTECT(t, name);
|
2007-09-24 01:39:03 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
GcByteArray* spec = makeByteArray(t, methodSpec);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
|
|
|
GcMethod* method
|
|
|
|
= cast<GcMethod>(t, findMethodInClass(t, class_, name, spec));
|
2009-06-03 00:55:12 +00:00
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
if (method == 0) {
|
2014-07-11 15:47:57 +00:00
|
|
|
throwNew(t,
|
|
|
|
GcNoSuchMethodError::Type,
|
|
|
|
"%s %s not found in %s",
|
|
|
|
methodName,
|
|
|
|
methodSpec,
|
|
|
|
class_->name()->body().begin());
|
2009-06-11 00:15:00 +00:00
|
|
|
} else {
|
|
|
|
return method;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcField* resolveField(Thread* t,
|
|
|
|
GcClass* class_,
|
|
|
|
const char* fieldName,
|
|
|
|
const char* fieldSpec)
|
2009-06-11 00:15:00 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, class_);
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
GcByteArray* name = makeByteArray(t, fieldName);
|
2009-06-11 00:15:00 +00:00
|
|
|
PROTECT(t, name);
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
GcByteArray* spec = makeByteArray(t, fieldSpec);
|
2009-06-11 00:15:00 +00:00
|
|
|
PROTECT(t, spec);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
|
|
|
GcField* field = cast<GcField>(
|
|
|
|
t, findInInterfaces(t, class_, name, spec, findFieldInClass));
|
2009-08-03 22:16:41 +00:00
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* c = class_;
|
2010-10-24 17:49:59 +00:00
|
|
|
PROTECT(t, c);
|
|
|
|
|
2014-06-21 04:16:33 +00:00
|
|
|
for (; c != 0 and field == 0; c = c->super()) {
|
2014-06-29 05:48:17 +00:00
|
|
|
field = cast<GcField>(t, findFieldInClass(t, c, name, spec));
|
2007-09-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
2010-12-27 22:55:23 +00:00
|
|
|
if (field == 0) {
|
2014-07-11 15:47:57 +00:00
|
|
|
throwNew(t,
|
|
|
|
GcNoSuchFieldError::Type,
|
|
|
|
"%s %s not found in %s",
|
|
|
|
fieldName,
|
|
|
|
fieldSpec,
|
|
|
|
class_->name()->body().begin());
|
2009-06-11 00:15:00 +00:00
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
return field;
|
2009-06-11 00:15:00 +00:00
|
|
|
}
|
2007-09-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
bool classNeedsInit(Thread* t, GcClass* c)
|
2009-07-20 20:12:38 +00:00
|
|
|
{
|
2014-05-29 04:17:25 +00:00
|
|
|
if (c->vmFlags() & NeedInitFlag) {
|
|
|
|
if (c->vmFlags() & InitFlag) {
|
2009-07-20 20:12:38 +00:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
bool preInitClass(Thread* t, GcClass* c)
|
2009-07-20 20:12:38 +00:00
|
|
|
{
|
2014-05-29 04:17:25 +00:00
|
|
|
int flags = c->vmFlags();
|
2011-04-10 20:46:53 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (c->vmFlags() & NeedInitFlag) {
|
|
|
|
if (c->vmFlags() & 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.
|
2014-05-29 04:17:25 +00:00
|
|
|
while (c->vmFlags() & InitFlag) {
|
2009-07-20 20:12:38 +00:00
|
|
|
ENTER(t, Thread::IdleState);
|
|
|
|
t->m->classLock->wait(t->systemThread, 0);
|
|
|
|
}
|
2014-05-29 04:17:25 +00:00
|
|
|
} else if (c->vmFlags() & InitErrorFlag) {
|
2014-07-11 15:47:57 +00:00
|
|
|
throwNew(
|
|
|
|
t, GcNoClassDefFoundError::Type, "%s", c->name()->body().begin());
|
2009-07-20 20:12:38 +00:00
|
|
|
} else {
|
2014-05-29 04:17:25 +00:00
|
|
|
c->vmFlags() |= InitFlag;
|
2009-07-20 20:12:38 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void postInitClass(Thread* t, GcClass* c)
|
2009-07-20 20:12:38 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, c);
|
|
|
|
ACQUIRE(t, t->m->classLock);
|
2010-09-22 19:58:46 +00:00
|
|
|
|
2014-07-10 19:27:18 +00:00
|
|
|
if (t->exception
|
2014-07-02 21:11:27 +00:00
|
|
|
and instanceOf(t, type(t, GcException::Type), t->exception)) {
|
2014-06-29 05:48:17 +00:00
|
|
|
c->vmFlags() |= NeedInitFlag | InitErrorFlag;
|
|
|
|
c->vmFlags() &= ~InitFlag;
|
2010-12-27 22:55:23 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
GcThrowable* exception = t->exception;
|
2010-12-20 23:49:45 +00:00
|
|
|
t->exception = 0;
|
2010-09-10 21:05:29 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
GcExceptionInInitializerError* initExecption
|
|
|
|
= makeThrowable(t, GcExceptionInInitializerError::Type, 0, 0, exception)
|
|
|
|
->as<GcExceptionInInitializerError>(t);
|
2014-06-29 05:48:17 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
initExecption->setException(t, exception->cause());
|
2013-12-06 05:28:13 +00:00
|
|
|
|
2014-06-26 01:42:16 +00:00
|
|
|
throw_(t, initExecption->as<GcThrowable>(t));
|
2009-07-20 20:12:38 +00:00
|
|
|
} else {
|
2014-06-29 05:48:17 +00:00
|
|
|
c->vmFlags() &= ~(NeedInitFlag | InitFlag);
|
2009-07-20 20:12:38 +00:00
|
|
|
}
|
|
|
|
t->m->classLock->notifyAll(t->systemThread);
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void initClass(Thread* t, GcClass* c)
|
2009-07-20 20:12:38 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, c);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcClass* super = c->super();
|
2011-04-01 01:43:49 +00:00
|
|
|
if (super) {
|
2014-06-29 05:48:17 +00:00
|
|
|
initClass(t, super);
|
2011-04-01 01:43:49 +00:00
|
|
|
}
|
|
|
|
|
2009-07-20 20:12:38 +00:00
|
|
|
if (preInitClass(t, c)) {
|
2014-06-29 05:48:17 +00:00
|
|
|
OBJECT_RESOURCE(t, c, postInitClass(t, cast<GcClass>(t, c)));
|
2010-12-27 22:55:23 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
GcMethod* initializer = classInitializer(t, c);
|
2011-04-01 01:43:49 +00:00
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* resolveObjectArrayClass(Thread* t,
|
|
|
|
GcClassLoader* loader,
|
|
|
|
GcClass* elementClass)
|
2010-11-27 23:27:30 +00:00
|
|
|
{
|
2011-11-18 15:38:19 +00:00
|
|
|
PROTECT(t, loader);
|
|
|
|
PROTECT(t, elementClass);
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
{
|
|
|
|
GcClass* arrayClass
|
|
|
|
= cast<GcClass>(t, getClassRuntimeData(t, elementClass)->arrayClass());
|
2010-11-27 23:27:30 +00:00
|
|
|
if (arrayClass) {
|
|
|
|
return arrayClass;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
GcByteArray* elementSpec = elementClass->name();
|
2010-11-27 23:27:30 +00:00
|
|
|
PROTECT(t, elementSpec);
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
GcByteArray* spec;
|
|
|
|
if (elementSpec->body()[0] == '[') {
|
|
|
|
spec = makeByteArray(t, elementSpec->length() + 1);
|
|
|
|
spec->body()[0] = '[';
|
2014-07-11 15:47:57 +00:00
|
|
|
memcpy(
|
|
|
|
&spec->body()[1], elementSpec->body().begin(), elementSpec->length());
|
2010-11-27 23:27:30 +00:00
|
|
|
} else {
|
2014-06-28 23:24:24 +00:00
|
|
|
spec = makeByteArray(t, elementSpec->length() + 3);
|
|
|
|
spec->body()[0] = '[';
|
|
|
|
spec->body()[1] = 'L';
|
|
|
|
memcpy(&spec->body()[2],
|
|
|
|
elementSpec->body().begin(),
|
|
|
|
elementSpec->length() - 1);
|
|
|
|
spec->body()[elementSpec->length() + 1] = ';';
|
|
|
|
spec->body()[elementSpec->length() + 2] = 0;
|
2010-11-27 23:27:30 +00:00
|
|
|
}
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* arrayClass = resolveClass(t, loader, spec);
|
2010-11-27 23:27:30 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
getClassRuntimeData(t, elementClass)->setArrayClass(t, arrayClass);
|
2010-11-27 23:27:30 +00:00
|
|
|
|
|
|
|
return arrayClass;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
object makeObjectArray(Thread* t, GcClass* elementClass, unsigned count)
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* arrayClass
|
|
|
|
= resolveObjectArrayClass(t, elementClass->loader(), 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);
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
object array = makeArray(t, count);
|
2007-07-14 17:31:01 +00:00
|
|
|
setObjectClass(t, array, arrayClass);
|
|
|
|
|
|
|
|
return array;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
static GcByteArray* getFieldName(Thread* t, object obj)
|
|
|
|
{
|
2014-06-26 02:17:27 +00:00
|
|
|
return reinterpret_cast<GcByteArray*>(cast<GcField>(t, obj)->name());
|
2014-06-29 05:48:17 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
static GcByteArray* getFieldSpec(Thread* t, object obj)
|
|
|
|
{
|
2014-06-26 02:17:27 +00:00
|
|
|
return reinterpret_cast<GcByteArray*>(cast<GcField>(t, obj)->spec());
|
2014-06-29 05:48:17 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
static GcByteArray* getMethodName(Thread* t, object obj)
|
|
|
|
{
|
2014-06-26 02:17:27 +00:00
|
|
|
return reinterpret_cast<GcByteArray*>(cast<GcMethod>(t, obj)->name());
|
2014-06-29 05:48:17 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
static GcByteArray* getMethodSpec(Thread* t, object obj)
|
|
|
|
{
|
2014-06-26 02:17:27 +00:00
|
|
|
return reinterpret_cast<GcByteArray*>(cast<GcMethod>(t, obj)->spec());
|
2014-06-29 05:48:17 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
object findFieldInClass(Thread* t,
|
|
|
|
GcClass* class_,
|
|
|
|
GcByteArray* name,
|
|
|
|
GcByteArray* spec)
|
2007-09-07 00:21:52 +00:00
|
|
|
{
|
2014-07-11 15:47:57 +00:00
|
|
|
return findInTable(t,
|
|
|
|
cast<GcArray>(t, class_->fieldTable()),
|
|
|
|
name,
|
|
|
|
spec,
|
|
|
|
getFieldName,
|
|
|
|
getFieldSpec);
|
|
|
|
}
|
|
|
|
|
|
|
|
object findMethodInClass(Thread* t,
|
|
|
|
GcClass* class_,
|
|
|
|
GcByteArray* name,
|
|
|
|
GcByteArray* spec)
|
2012-03-27 00:06:16 +00:00
|
|
|
{
|
2014-07-11 15:47:57 +00:00
|
|
|
return findInTable(t,
|
|
|
|
cast<GcArray>(t, class_->methodTable()),
|
|
|
|
name,
|
|
|
|
spec,
|
|
|
|
getMethodName,
|
|
|
|
getMethodSpec);
|
|
|
|
}
|
|
|
|
|
|
|
|
object findInHierarchyOrNull(
|
|
|
|
Thread* t,
|
|
|
|
GcClass* class_,
|
|
|
|
GcByteArray* name,
|
|
|
|
GcByteArray* spec,
|
|
|
|
object (*find)(Thread*, GcClass*, GcByteArray*, GcByteArray*))
|
2007-09-07 00:21:52 +00:00
|
|
|
{
|
2014-05-29 04:17:25 +00:00
|
|
|
GcClass* originalClass = class_;
|
2007-09-07 00:21:52 +00:00
|
|
|
|
|
|
|
object o = 0;
|
2014-07-11 15:47:57 +00:00
|
|
|
if ((class_->flags() & ACC_INTERFACE) and class_->virtualTable()) {
|
|
|
|
o = findInTable(t,
|
|
|
|
cast<GcArray>(t, class_->virtualTable()),
|
|
|
|
name,
|
|
|
|
spec,
|
|
|
|
getMethodName,
|
|
|
|
getMethodSpec);
|
2008-11-11 15:20:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (o == 0) {
|
2014-06-21 04:16:33 +00:00
|
|
|
for (; o == 0 and class_; class_ = class_->super()) {
|
2007-09-07 00:21:52 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
unsigned parameterFootprint(Thread* t, const char* s, bool static_)
|
2007-11-20 22:24:02 +00:00
|
|
|
{
|
|
|
|
unsigned footprint = 0;
|
|
|
|
for (MethodSpecIterator it(t, s); it.hasNext();) {
|
|
|
|
switch (*it.next()) {
|
|
|
|
case 'J':
|
|
|
|
case 'D':
|
|
|
|
footprint += 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2014-07-11 15:50:18 +00:00
|
|
|
++footprint;
|
|
|
|
break;
|
2007-11-20 22:24:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (not static_) {
|
2014-07-11 15:50:18 +00:00
|
|
|
++footprint;
|
2007-11-20 22:24:02 +00:00
|
|
|
}
|
|
|
|
return footprint;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object))
|
2007-07-14 17:31:01 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
GcFinalizer* f = makeFinalizer(t, 0, function, 0, 0, 0);
|
|
|
|
f->target() = target;
|
2014-07-02 21:11:27 +00:00
|
|
|
f->next() = t->m->finalizers;
|
2007-09-24 01:39:03 +00:00
|
|
|
t->m->finalizers = f;
|
2007-07-11 04:19:26 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcMonitor* objectMonitor(Thread* t, object o, bool createNew)
|
2007-07-06 23:50:26 +00:00
|
|
|
{
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, t->state == Thread::ActiveState);
|
2008-01-18 01:27:44 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
object m = hashMapFind(t, roots(t)->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
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
return cast<GcMonitor>(t, 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);
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
{
|
|
|
|
ENTER(t, Thread::ExclusiveState);
|
2007-07-06 23:50:26 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
m = hashMapFind(t, roots(t)->monitorMap(), o, objectHash, objectEqual);
|
2010-09-14 16:49:41 +00:00
|
|
|
|
2010-02-05 00:56:21 +00:00
|
|
|
if (m) {
|
|
|
|
if (DebugMonitors) {
|
2014-07-11 15:50:18 +00:00
|
|
|
fprintf(
|
|
|
|
stderr, "found monitor %p for object %x\n", m, objectHash(t, o));
|
2010-02-05 00:56:21 +00:00
|
|
|
}
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
return cast<GcMonitor>(t, m);
|
2010-02-05 00:56:21 +00:00
|
|
|
}
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
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) {
|
2014-07-11 15:50:18 +00:00
|
|
|
fprintf(stderr, "made monitor %p for object %x\n", m, objectHash(t, o));
|
2007-11-29 15:03:45 +00:00
|
|
|
}
|
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
hashMapInsert(t, roots(t)->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
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
return cast<GcMonitor>(t, m);
|
2007-11-27 22:23:00 +00:00
|
|
|
} else {
|
|
|
|
return 0;
|
2007-07-06 23:50:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
object intern(Thread* t, object s)
|
2007-07-29 00:02:32 +00:00
|
|
|
{
|
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
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcTriple* n
|
|
|
|
= hashMapFindNode(t, roots(t)->stringMap(), s, stringHash, stringEqual);
|
2010-09-14 16:49:41 +00:00
|
|
|
|
2007-07-29 00:02:32 +00:00
|
|
|
if (n) {
|
2014-07-02 21:11:27 +00:00
|
|
|
return cast<GcJreference>(t, n->first())->target();
|
2007-07-29 00:02:32 +00:00
|
|
|
} else {
|
2014-06-30 01:44:41 +00:00
|
|
|
hashMapInsert(t, roots(t)->stringMap(), s, 0, stringHash);
|
2007-07-29 00:02:32 +00:00
|
|
|
addFinalizer(t, s, removeString);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-10 13:38:41 +00:00
|
|
|
object clone(Thread* t, object o)
|
|
|
|
{
|
|
|
|
PROTECT(t, o);
|
|
|
|
|
|
|
|
GcClass* class_ = objectClass(t, o);
|
|
|
|
unsigned size = baseSize(t, o, class_) * BytesPerWord;
|
|
|
|
object clone;
|
|
|
|
|
|
|
|
if (class_->arrayElementSize()) {
|
|
|
|
clone = static_cast<object>(allocate(t, size, class_->objectMask()));
|
|
|
|
memcpy(clone, o, size);
|
|
|
|
// clear any object header flags:
|
|
|
|
setObjectClass(t, o, objectClass(t, o));
|
|
|
|
} else if (instanceOf(t, type(t, GcCloneable::Type), o)) {
|
|
|
|
clone = make(t, class_);
|
|
|
|
memcpy(reinterpret_cast<void**>(clone) + 1,
|
|
|
|
reinterpret_cast<void**>(o) + 1,
|
|
|
|
size - BytesPerWord);
|
|
|
|
} else {
|
|
|
|
GcByteArray* classNameSlash = objectClass(t, o)->name();
|
|
|
|
THREAD_RUNTIME_ARRAY(t, char, classNameDot, classNameSlash->length());
|
|
|
|
replace('/',
|
|
|
|
'.',
|
|
|
|
RUNTIME_ARRAY_BODY(classNameDot),
|
|
|
|
reinterpret_cast<char*>(classNameSlash->body().begin()));
|
|
|
|
throwNew(t,
|
|
|
|
GcCloneNotSupportedException::Type,
|
|
|
|
"%s",
|
|
|
|
RUNTIME_ARRAY_BODY(classNameDot));
|
|
|
|
}
|
|
|
|
|
|
|
|
return clone;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void walk(Thread* t, Heap::Walker* w, object o, unsigned start)
|
2008-11-21 23:20:35 +00:00
|
|
|
{
|
2014-06-29 05:48:17 +00:00
|
|
|
GcClass* class_ = t->m->heap->follow(objectClass(t, o));
|
|
|
|
GcIntArray* objectMask = t->m->heap->follow(class_->objectMask());
|
2008-11-21 23:20:35 +00:00
|
|
|
|
2009-05-17 23:43:48 +00:00
|
|
|
bool more = true;
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
if (objectMask) {
|
2014-05-29 04:17:25 +00:00
|
|
|
unsigned fixedSize = class_->fixedSize();
|
|
|
|
unsigned arrayElementSize = class_->arrayElementSize();
|
2014-07-11 15:50:18 +00:00
|
|
|
unsigned arrayLength = (arrayElementSize ? fieldAtOffset<uintptr_t>(
|
|
|
|
o, fixedSize - BytesPerWord)
|
|
|
|
: 0);
|
2008-11-21 23:20:35 +00:00
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, uint32_t, mask, objectMask->length());
|
2014-07-11 15:47:57 +00:00
|
|
|
memcpy(RUNTIME_ARRAY_BODY(mask),
|
|
|
|
objectMask->body().begin(),
|
2014-06-29 05:48:17 +00:00
|
|
|
objectMask->length() * 4);
|
2008-11-21 23:20:35 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
more = ::walk(t,
|
|
|
|
w,
|
|
|
|
RUNTIME_ARRAY_BODY(mask),
|
|
|
|
fixedSize,
|
|
|
|
arrayElementSize,
|
|
|
|
arrayLength,
|
|
|
|
start);
|
2014-05-29 04:17:25 +00:00
|
|
|
} else if (class_->vmFlags() & SingletonFlag) {
|
2014-06-29 05:48:17 +00:00
|
|
|
GcSingleton* s = cast<GcSingleton>(t, o);
|
|
|
|
unsigned length = s->length();
|
2008-11-21 23:20:35 +00:00
|
|
|
if (length) {
|
2014-07-11 15:47:57 +00:00
|
|
|
more = ::walk(t,
|
|
|
|
w,
|
|
|
|
singletonMask(t, s),
|
|
|
|
(singletonCount(t, s) + 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
|
|
|
|
2014-05-29 04:17:25 +00:00
|
|
|
if (more and class_->vmFlags() & 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
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
int walkNext(Thread* t, object o, int previous)
|
2008-11-11 15:20:49 +00:00
|
|
|
{
|
2014-07-11 15:50:18 +00:00
|
|
|
class Walker : public Heap::Walker {
|
2008-11-11 15:20:49 +00:00
|
|
|
public:
|
2014-07-11 15:50:18 +00:00
|
|
|
Walker() : value(-1)
|
|
|
|
{
|
|
|
|
}
|
2008-11-11 15:20:49 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
bool visit(unsigned offset)
|
|
|
|
{
|
2008-11-11 15:20:49 +00:00
|
|
|
value = offset;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int value;
|
|
|
|
} walker;
|
|
|
|
|
|
|
|
walk(t, &walker, o, previous + 1);
|
|
|
|
return walker.value;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void visitRoots(Machine* m, Heap::Visitor* v)
|
2008-11-11 15:20:49 +00:00
|
|
|
{
|
|
|
|
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) {
|
2012-02-29 18:51:30 +00:00
|
|
|
if (not r->weak) {
|
|
|
|
v->visit(&(r->target));
|
|
|
|
}
|
2009-05-03 20:57:11 +00:00
|
|
|
}
|
2008-11-11 15:20:49 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void logTrace(FILE* f, const char* fmt, ...)
|
2013-02-05 06:41:37 +00:00
|
|
|
{
|
2014-07-11 15:50:18 +00:00
|
|
|
va_list a;
|
|
|
|
va_start(a, fmt);
|
2013-02-05 06:41:37 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2014-07-11 15:50:18 +00:00
|
|
|
const unsigned length = _vscprintf(fmt, a);
|
2013-02-05 06:41:37 +00:00
|
|
|
#else
|
2014-07-11 15:50:18 +00:00
|
|
|
const unsigned length = vsnprintf(0, 0, fmt, a);
|
2013-02-05 06:41:37 +00:00
|
|
|
#endif
|
2014-07-11 15:50:18 +00:00
|
|
|
va_end(a);
|
2013-02-06 18:40:06 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
RUNTIME_ARRAY(char, buffer, length + 1);
|
|
|
|
va_start(a, fmt);
|
|
|
|
vsnprintf(RUNTIME_ARRAY_BODY(buffer), length + 1, fmt, a);
|
|
|
|
va_end(a);
|
|
|
|
RUNTIME_ARRAY_BODY(buffer)[length] = 0;
|
2013-02-05 06:41:37 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
::fprintf(f, "%s", RUNTIME_ARRAY_BODY(buffer));
|
2013-02-05 06:41:37 +00:00
|
|
|
#ifdef PLATFORM_WINDOWS
|
2014-07-11 15:50:18 +00:00
|
|
|
::OutputDebugStringA(RUNTIME_ARRAY_BODY(buffer));
|
2013-02-05 06:41:37 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void printTrace(Thread* t, GcThrowable* exception)
|
2007-07-24 03:16:59 +00:00
|
|
|
{
|
2007-10-12 20:54:37 +00:00
|
|
|
if (exception == 0) {
|
2014-05-29 04:17:25 +00:00
|
|
|
exception = makeThrowable(t, GcNullPointerException::Type);
|
2007-10-12 20:54:37 +00:00
|
|
|
}
|
2007-10-13 00:22:52 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
for (GcThrowable* e = exception; e; e = e->cause()) {
|
2007-07-24 03:16:59 +00:00
|
|
|
if (e != exception) {
|
2013-02-05 06:41:37 +00:00
|
|
|
logTrace(errorLog(t), "caused by: ");
|
2007-07-24 03:16:59 +00:00
|
|
|
}
|
|
|
|
|
2014-06-21 04:16:33 +00:00
|
|
|
logTrace(errorLog(t), "%s", objectClass(t, e)->name()->body().begin());
|
2013-01-30 08:42:05 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
if (e->message()) {
|
|
|
|
GcString* m = e->message();
|
|
|
|
THREAD_RUNTIME_ARRAY(t, char, message, m->length(t) + 1);
|
2009-08-27 00:26:44 +00:00
|
|
|
stringChars(t, m, RUNTIME_ARRAY_BODY(message));
|
2013-02-05 06:41:37 +00:00
|
|
|
logTrace(errorLog(t), ": %s\n", RUNTIME_ARRAY_BODY(message));
|
2007-07-24 03:16:59 +00:00
|
|
|
} else {
|
2013-02-05 06:41:37 +00:00
|
|
|
logTrace(errorLog(t), "\n");
|
2007-07-24 03:16:59 +00:00
|
|
|
}
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
object trace = e->trace();
|
2011-03-04 22:58:10 +00:00
|
|
|
if (trace) {
|
|
|
|
for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) {
|
2014-07-11 15:47:57 +00:00
|
|
|
GcTraceElement* e
|
|
|
|
= cast<GcTraceElement>(t, objectArrayBody(t, trace, i));
|
2014-06-29 05:48:17 +00:00
|
|
|
GcMethod* m = cast<GcMethod>(t, e->method());
|
|
|
|
const int8_t* class_ = m->class_()->name()->body().begin();
|
|
|
|
const int8_t* method = m->name()->body().begin();
|
2014-07-11 15:47:57 +00:00
|
|
|
int line = t->m->processor->lineNumber(t, m, e->ip());
|
2011-03-04 22:58:10 +00:00
|
|
|
|
2013-02-05 06:41:37 +00:00
|
|
|
logTrace(errorLog(t), " at %s.%s ", class_, method);
|
2011-03-04 22:58:10 +00:00
|
|
|
|
|
|
|
switch (line) {
|
|
|
|
case NativeLine:
|
2013-02-05 06:41:37 +00:00
|
|
|
logTrace(errorLog(t), "(native)\n");
|
2011-03-04 22:58:10 +00:00
|
|
|
break;
|
|
|
|
case UnknownLine:
|
2013-02-05 06:41:37 +00:00
|
|
|
logTrace(errorLog(t), "(unknown line)\n");
|
2011-03-04 22:58:10 +00:00
|
|
|
break;
|
|
|
|
default:
|
2013-02-05 06:41:37 +00:00
|
|
|
logTrace(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
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
if (e == e->cause()) {
|
2010-09-10 21:05:29 +00:00
|
|
|
break;
|
|
|
|
}
|
2007-07-24 03:16:59 +00:00
|
|
|
}
|
2010-12-01 03:27:36 +00:00
|
|
|
|
2013-02-05 06:41:37 +00:00
|
|
|
::fflush(errorLog(t));
|
2007-07-24 03:16:59 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
object makeTrace(Thread* t, Processor::StackWalker* walker)
|
2007-09-24 01:39:03 +00:00
|
|
|
{
|
2014-07-11 15:50:18 +00:00
|
|
|
class Visitor : public Processor::StackVisitor {
|
2007-11-25 23:00:55 +00:00
|
|
|
public:
|
2014-07-11 15:50:18 +00:00
|
|
|
Visitor(Thread* t) : t(t), trace(0), index(0), protector(t, &trace)
|
|
|
|
{
|
|
|
|
}
|
2007-09-24 13:46:48 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
virtual bool visit(Processor::StackWalker* walker)
|
|
|
|
{
|
2007-11-25 23:00:55 +00:00
|
|
|
if (trace == 0) {
|
2010-09-14 16:49:41 +00:00
|
|
|
trace = makeObjectArray(t, walker->count());
|
2014-06-04 01:52:01 +00:00
|
|
|
assertT(t, trace);
|
2007-11-25 23:00:55 +00:00
|
|
|
}
|
2007-09-24 01:39:03 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
GcTraceElement* e = makeTraceElement(t, walker->method(), walker->ip());
|
|
|
|
assertT(t, index < objectArrayLength(t, trace));
|
|
|
|
reinterpret_cast<GcArray*>(trace)->setBodyElement(t, index, e);
|
2014-07-11 15:50:18 +00:00
|
|
|
++index;
|
2007-11-25 23:00:55 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
object makeTrace(Thread* t, Thread* target)
|
2007-11-25 23:00:55 +00:00
|
|
|
{
|
2014-07-11 15:50:18 +00:00
|
|
|
class Visitor : public Processor::StackVisitor {
|
2007-11-25 23:00:55 +00:00
|
|
|
public:
|
2014-07-11 15:50:18 +00:00
|
|
|
Visitor(Thread* t) : t(t), trace(0)
|
|
|
|
{
|
|
|
|
}
|
2007-11-25 23:00:55 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void runFinalizeThread(Thread* t)
|
2009-08-24 23:51:31 +00:00
|
|
|
{
|
2014-06-29 05:48:17 +00:00
|
|
|
GcFinalizer* finalizeList = 0;
|
2011-03-26 01:11:38 +00:00
|
|
|
PROTECT(t, finalizeList);
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
GcCleaner* cleanList = 0;
|
2011-03-26 01:11:38 +00:00
|
|
|
PROTECT(t, cleanList);
|
2009-08-24 23:51:31 +00:00
|
|
|
|
|
|
|
while (true) {
|
2014-07-11 15:50:18 +00:00
|
|
|
{
|
|
|
|
ACQUIRE(t, t->m->stateLock);
|
2009-08-24 23:51:31 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
while (t->m->finalizeThread and roots(t)->objectsToFinalize() == 0
|
|
|
|
and roots(t)->objectsToClean() == 0) {
|
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 {
|
2014-06-30 01:44:41 +00:00
|
|
|
finalizeList = roots(t)->objectsToFinalize();
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(t)->setObjectsToFinalize(t, 0);
|
2011-03-26 01:11:38 +00:00
|
|
|
|
2014-06-30 01:44:41 +00:00
|
|
|
cleanList = roots(t)->objectsToClean();
|
2014-06-26 01:42:16 +00:00
|
|
|
roots(t)->setObjectsToClean(t, 0);
|
2009-08-24 23:51:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
for (; finalizeList; finalizeList = finalizeList->queueNext()) {
|
|
|
|
finalizeObject(t, finalizeList->queueTarget(), "finalize");
|
2011-03-26 01:11:38 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 05:48:17 +00:00
|
|
|
for (; cleanList; cleanList = cleanList->queueNext()) {
|
2014-07-02 21:11:27 +00:00
|
|
|
finalizeObject(t, cleanList, "clean");
|
2009-08-24 23:51:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
object parseUtf8(Thread* t, const char* data, unsigned length)
|
2010-09-10 21:05:29 +00:00
|
|
|
{
|
2014-07-11 15:50:18 +00:00
|
|
|
class Client : public Stream::Client {
|
2010-09-10 21:05:29 +00:00
|
|
|
public:
|
2014-07-11 15:50:18 +00:00
|
|
|
Client(Thread* t) : t(t)
|
|
|
|
{
|
|
|
|
}
|
2010-09-10 21:05:29 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
virtual void handleError()
|
|
|
|
{
|
|
|
|
if (false)
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
object parseUtf8(Thread* t, GcByteArray* array)
|
2013-02-03 21:09:29 +00:00
|
|
|
{
|
2014-06-28 23:24:24 +00:00
|
|
|
for (unsigned i = 0; i < array->length() - 1; ++i) {
|
|
|
|
if (array->body()[i] & 0x80) {
|
2013-02-03 21:09:29 +00:00
|
|
|
goto slow_path;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
return array;
|
2013-02-03 21:09:29 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
slow_path:
|
|
|
|
class Client : public Stream::Client {
|
2013-02-03 21:09:29 +00:00
|
|
|
public:
|
2014-07-11 15:50:18 +00:00
|
|
|
Client(Thread* t) : t(t)
|
|
|
|
{
|
|
|
|
}
|
2013-02-03 21:09:29 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
virtual void handleError()
|
|
|
|
{
|
|
|
|
if (false)
|
|
|
|
abort(t);
|
2013-02-03 21:09:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Thread* t;
|
|
|
|
} client(t);
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
class MyStream : public AbstractStream {
|
2013-02-03 21:09:29 +00:00
|
|
|
public:
|
2014-07-11 15:50:18 +00:00
|
|
|
class MyProtector : public Thread::Protector {
|
2013-02-03 21:09:29 +00:00
|
|
|
public:
|
2014-07-11 15:50:18 +00:00
|
|
|
MyProtector(Thread* t, MyStream* s) : Protector(t), s(s)
|
|
|
|
{
|
|
|
|
}
|
2013-02-03 21:09:29 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
virtual void visit(Heap::Visitor* v)
|
|
|
|
{
|
2013-02-03 21:09:29 +00:00
|
|
|
v->visit(&(s->array));
|
|
|
|
}
|
|
|
|
|
|
|
|
MyStream* s;
|
|
|
|
};
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
MyStream(Thread* t, Client* client, GcByteArray* array)
|
|
|
|
: AbstractStream(client, array->length() - 1),
|
|
|
|
array(array),
|
|
|
|
protector(t, this)
|
2014-07-11 15:50:18 +00:00
|
|
|
{
|
|
|
|
}
|
2013-02-03 21:09:29 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
virtual void copy(uint8_t* dst, unsigned offset, unsigned size)
|
|
|
|
{
|
2014-06-28 23:24:24 +00:00
|
|
|
memcpy(dst, &array->body()[offset], size);
|
2013-02-03 21:09:29 +00:00
|
|
|
}
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
GcByteArray* array;
|
2013-02-03 21:09:29 +00:00
|
|
|
MyProtector protector;
|
|
|
|
} s(t, &client, array);
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
return ::parseUtf8(t, s, array->length() - 1);
|
2013-02-03 21:09:29 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcMethod* getCaller(Thread* t, unsigned target, bool skipMethodInvoke)
|
2010-09-25 21:54:01 +00:00
|
|
|
{
|
2014-04-23 21:22:10 +00:00
|
|
|
if (static_cast<int>(target) == -1) {
|
|
|
|
target = 2;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
class Visitor : public Processor::StackVisitor {
|
2010-09-25 21:54:01 +00:00
|
|
|
public:
|
2014-07-11 15:50:18 +00:00
|
|
|
Visitor(Thread* t, unsigned target, bool skipMethodInvoke)
|
|
|
|
: t(t),
|
|
|
|
method(0),
|
|
|
|
count(0),
|
|
|
|
target(target),
|
|
|
|
skipMethodInvoke(skipMethodInvoke)
|
|
|
|
{
|
|
|
|
}
|
2010-09-25 21:54:01 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
virtual bool visit(Processor::StackWalker* walker)
|
|
|
|
{
|
2012-09-23 02:22:33 +00:00
|
|
|
if (skipMethodInvoke
|
2014-07-11 15:47:57 +00:00
|
|
|
and walker->method()->class_() == type(t, GcJmethod::Type)
|
2014-06-21 04:16:33 +00:00
|
|
|
and strcmp(walker->method()->name()->body().begin(),
|
2014-05-29 04:17:25 +00:00
|
|
|
reinterpret_cast<const int8_t*>("invoke")) == 0) {
|
2012-09-23 02:22:33 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-09-25 21:54:01 +00:00
|
|
|
if (count == target) {
|
|
|
|
method = walker->method();
|
|
|
|
return false;
|
|
|
|
} else {
|
2014-07-11 15:50:18 +00:00
|
|
|
++count;
|
2010-09-25 21:54:01 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Thread* t;
|
2014-05-29 04:17:25 +00:00
|
|
|
GcMethod* method;
|
2010-09-25 21:54:01 +00:00
|
|
|
unsigned count;
|
|
|
|
unsigned target;
|
2012-09-23 02:22:33 +00:00
|
|
|
bool skipMethodInvoke;
|
2014-07-11 15:50:18 +00:00
|
|
|
} v(t, target, skipMethodInvoke);
|
2010-09-25 21:54:01 +00:00
|
|
|
|
|
|
|
t->m->processor->walkStack(t, &v);
|
|
|
|
|
|
|
|
return v.method;
|
|
|
|
}
|
|
|
|
|
support AOT-compilation of Java 8 lambda expressions
These expressions are tricky because they rely on invokedynamic, which
normally implies runtime code generation. However, since lambdas
don't actually use the "dynamicness" of invokedynamic, we can convert
them into static calls to synthetic classes at compile time.
Since I had already written code to synthesize such classes in Java
and I didn't want to rewrite it in C++, I needed to add support for
running Java code to the bootimage generator. And since the primary
VM used by the generator is purpose-built to generate AOT-compiled
code for a specific target architecture and is not capable of
generating or running JIT-compiled code for the host architecture, I
added support for loading a second, independent, host-specific VM for
running Java code.
The rest of the patch handles the fact that each method compilation
might cause new, synthetic classes to be created, so we need to make
sure those classes and their methods are included in the final heap
and code images. This required breaking some giant code blocks out of
makeCodeImage into their own methods, which makes the diff look
scarier than it really is.
2015-09-13 02:15:46 +00:00
|
|
|
GcClass* defineClass(Thread* t,
|
|
|
|
GcClassLoader* loader,
|
|
|
|
const uint8_t* buffer,
|
|
|
|
unsigned length)
|
2010-09-10 21:05:29 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, loader);
|
|
|
|
|
support AOT-compilation of Java 8 lambda expressions
These expressions are tricky because they rely on invokedynamic, which
normally implies runtime code generation. However, since lambdas
don't actually use the "dynamicness" of invokedynamic, we can convert
them into static calls to synthetic classes at compile time.
Since I had already written code to synthesize such classes in Java
and I didn't want to rewrite it in C++, I needed to add support for
running Java code to the bootimage generator. And since the primary
VM used by the generator is purpose-built to generate AOT-compiled
code for a specific target architecture and is not capable of
generating or running JIT-compiled code for the host architecture, I
added support for loading a second, independent, host-specific VM for
running Java code.
The rest of the patch handles the fact that each method compilation
might cause new, synthetic classes to be created, so we need to make
sure those classes and their methods are included in the final heap
and code images. This required breaking some giant code blocks out of
makeCodeImage into their own methods, which makes the diff look
scarier than it really is.
2015-09-13 02:15:46 +00:00
|
|
|
GcClass* c = parseClass(t, loader, buffer, length);
|
2014-07-11 15:50:18 +00:00
|
|
|
|
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);
|
|
|
|
|
support AOT-compilation of Java 8 lambda expressions
These expressions are tricky because they rely on invokedynamic, which
normally implies runtime code generation. However, since lambdas
don't actually use the "dynamicness" of invokedynamic, we can convert
them into static calls to synthetic classes at compile time.
Since I had already written code to synthesize such classes in Java
and I didn't want to rewrite it in C++, I needed to add support for
running Java code to the bootimage generator. And since the primary
VM used by the generator is purpose-built to generate AOT-compiled
code for a specific target architecture and is not capable of
generating or running JIT-compiled code for the host architecture, I
added support for loading a second, independent, host-specific VM for
running Java code.
The rest of the patch handles the fact that each method compilation
might cause new, synthetic classes to be created, so we need to make
sure those classes and their methods are included in the final heap
and code images. This required breaking some giant code blocks out of
makeCodeImage into their own methods, which makes the diff look
scarier than it really is.
2015-09-13 02:15:46 +00:00
|
|
|
saveLoadedClass(t, loader, c);
|
2010-09-10 21:05:29 +00:00
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void populateMultiArray(Thread* t,
|
|
|
|
object array,
|
|
|
|
int32_t* counts,
|
|
|
|
unsigned index,
|
|
|
|
unsigned dimensions)
|
2011-03-26 17:15:52 +00:00
|
|
|
{
|
|
|
|
if (index + 1 == dimensions or counts[index] == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PROTECT(t, array);
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
GcByteArray* spec = objectClass(t, array)->name();
|
2011-03-26 17:15:52 +00:00
|
|
|
PROTECT(t, spec);
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
GcByteArray* elementSpec = makeByteArray(t, spec->length() - 1);
|
2014-07-11 15:47:57 +00:00
|
|
|
memcpy(elementSpec->body().begin(), &spec->body()[1], spec->length() - 1);
|
2011-03-26 17:15:52 +00:00
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
GcClass* class_
|
|
|
|
= resolveClass(t, objectClass(t, array)->loader(), elementSpec);
|
2011-03-26 17:15:52 +00:00
|
|
|
PROTECT(t, class_);
|
|
|
|
|
|
|
|
for (int32_t i = 0; i < counts[index]; ++i) {
|
2014-07-11 15:47:57 +00:00
|
|
|
GcArray* a = makeArray(
|
|
|
|
t,
|
|
|
|
ceilingDivide(counts[index + 1] * class_->arrayElementSize(),
|
|
|
|
BytesPerWord));
|
2014-06-29 05:48:17 +00:00
|
|
|
a->length() = counts[index + 1];
|
2014-07-02 21:11:27 +00:00
|
|
|
setObjectClass(t, a, class_);
|
|
|
|
setField(t, array, ArrayBody + (i * BytesPerWord), a);
|
2014-06-26 01:42:16 +00:00
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
populateMultiArray(t, a, counts, index + 1, dimensions);
|
2011-03-26 17:15:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
object interruptLock(Thread* t, GcThread* thread)
|
2013-04-23 19:47:15 +00:00
|
|
|
{
|
2014-06-28 23:24:24 +00:00
|
|
|
object lock = thread->interruptLock();
|
2013-04-23 19:47:15 +00:00
|
|
|
|
|
|
|
loadMemoryBarrier();
|
|
|
|
|
|
|
|
if (lock == 0) {
|
|
|
|
PROTECT(t, thread);
|
|
|
|
ACQUIRE(t, t->m->referenceLock);
|
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
if (thread->interruptLock() == 0) {
|
2014-07-02 21:11:27 +00:00
|
|
|
object head = makeMonitorNode(t, 0, 0);
|
2014-06-29 05:48:17 +00:00
|
|
|
GcMonitor* lock = makeMonitor(t, 0, 0, 0, head, head, 0);
|
2013-04-23 19:47:15 +00:00
|
|
|
|
|
|
|
storeStoreMemoryBarrier();
|
|
|
|
|
2014-07-02 21:11:27 +00:00
|
|
|
thread->setInterruptLock(t, lock);
|
2013-04-23 19:47:15 +00:00
|
|
|
}
|
|
|
|
}
|
2014-07-11 15:47:57 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
return thread->interruptLock();
|
2013-04-23 19:47:15 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void clearInterrupted(Thread* t)
|
2013-04-23 19:47:15 +00:00
|
|
|
{
|
2014-06-28 23:24:24 +00:00
|
|
|
monitorAcquire(t, cast<GcMonitor>(t, interruptLock(t, t->javaThread)));
|
|
|
|
t->javaThread->interrupted() = false;
|
|
|
|
monitorRelease(t, cast<GcMonitor>(t, interruptLock(t, t->javaThread)));
|
2013-04-23 19:47:15 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
void threadInterrupt(Thread* t, GcThread* thread)
|
2013-04-23 19:47:15 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, thread);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
monitorAcquire(t, cast<GcMonitor>(t, interruptLock(t, thread)));
|
|
|
|
Thread* p = reinterpret_cast<Thread*>(thread->peer());
|
2013-04-23 19:47:15 +00:00
|
|
|
if (p) {
|
|
|
|
interrupt(t, p);
|
|
|
|
}
|
2014-06-28 23:24:24 +00:00
|
|
|
thread->interrupted() = true;
|
|
|
|
monitorRelease(t, cast<GcMonitor>(t, interruptLock(t, thread)));
|
2013-04-23 19:47:15 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:47:57 +00:00
|
|
|
bool threadIsInterrupted(Thread* t, GcThread* thread, bool clear)
|
2013-04-23 19:47:15 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, thread);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
2014-06-28 23:24:24 +00:00
|
|
|
monitorAcquire(t, cast<GcMonitor>(t, interruptLock(t, thread)));
|
|
|
|
bool v = thread->interrupted();
|
2013-04-23 19:47:15 +00:00
|
|
|
if (clear) {
|
2014-06-28 23:24:24 +00:00
|
|
|
thread->interrupted() = false;
|
2013-04-23 19:47:15 +00:00
|
|
|
}
|
2014-06-28 23:24:24 +00:00
|
|
|
monitorRelease(t, cast<GcMonitor>(t, interruptLock(t, thread)));
|
2013-04-23 19:47:15 +00:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
2014-07-12 22:03:11 +00:00
|
|
|
GcJclass* getDeclaringClass(Thread* t, GcClass* c)
|
|
|
|
{
|
|
|
|
GcClassAddendum* addendum = c->addendum();
|
|
|
|
if (addendum) {
|
|
|
|
GcArray* table = cast<GcArray>(t, addendum->innerClassTable());
|
|
|
|
if (table) {
|
|
|
|
for (unsigned i = 0; i < table->length(); ++i) {
|
|
|
|
GcInnerClassReference* reference
|
|
|
|
= cast<GcInnerClassReference>(t, table->body()[i]);
|
|
|
|
if (reference->outer()
|
|
|
|
and strcmp(reference->inner()->body().begin(),
|
|
|
|
c->name()->body().begin()) == 0) {
|
|
|
|
return getJClass(t, resolveClass(t, c->loader(), reference->outer()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// Called when interpreting invokedynamic. `invocation` points to
|
|
|
|
// static data in the bootstrap method table, which in turn points to
|
|
|
|
// a bootstrap method and stores additional data to be passed to
|
|
|
|
// it. `resolveDynamic` will then call this bootstrap method after
|
|
|
|
// resolving the arguments as required. The called method is assumed
|
|
|
|
// to be a lambda `metafactory` or `altMetafactory`.
|
|
|
|
//
|
|
|
|
// Note that capture/bridging etc happens within the bootstrap method,
|
|
|
|
// this is just the code that dispatches to it.
|
|
|
|
//
|
|
|
|
// Returns the CallSite returned by the bootstrap method.
|
2015-08-06 23:22:14 +00:00
|
|
|
GcCallSite* resolveDynamic(Thread* t, GcInvocation* invocation)
|
|
|
|
{
|
|
|
|
PROTECT(t, invocation);
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// Use the invocation's Class to get the bootstrap method table and get a classloader.
|
2015-08-06 23:22:14 +00:00
|
|
|
GcClass* c = invocation->class_();
|
|
|
|
PROTECT(t, c);
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// First element points to the bootstrap method. The rest are static data passed to the BSM.
|
2015-08-06 23:22:14 +00:00
|
|
|
GcCharArray* bootstrapArray = cast<GcCharArray>(
|
|
|
|
t,
|
|
|
|
cast<GcArray>(t, c->addendum()->bootstrapMethodTable())
|
|
|
|
->body()[invocation->bootstrap()]);
|
|
|
|
|
|
|
|
PROTECT(t, bootstrapArray);
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// Resolve the bootstrap method itself.
|
2017-07-10 16:01:56 +00:00
|
|
|
GcMethod* bootstrap = cast<GcMethodHandle>(t,
|
2015-08-06 23:22:14 +00:00
|
|
|
resolve(t,
|
|
|
|
c->loader(),
|
|
|
|
invocation->pool(),
|
|
|
|
bootstrapArray->body()[0],
|
|
|
|
findMethodInClass,
|
2017-07-10 16:01:56 +00:00
|
|
|
GcNoSuchMethodError::Type))->method();
|
2015-08-06 23:22:14 +00:00
|
|
|
PROTECT(t, bootstrap);
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// Caller context info to be passed to the bootstrap method.
|
2015-08-06 23:22:14 +00:00
|
|
|
GcLookup* lookup
|
|
|
|
= makeLookup(t, c, ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC);
|
|
|
|
PROTECT(t, lookup);
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// The name of the linked-to method.
|
2015-08-06 23:22:14 +00:00
|
|
|
GcByteArray* nameBytes = invocation->template_()->name();
|
|
|
|
GcString* name
|
|
|
|
= t->m->classpath->makeString(t, nameBytes, 0, nameBytes->length() - 1);
|
|
|
|
PROTECT(t, name);
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// This is the type of the linked-to method (e.g. lambda).
|
2015-08-06 23:22:14 +00:00
|
|
|
GcMethodType* type = makeMethodType(
|
|
|
|
t, c->loader(), invocation->template_()->spec(), 0, 0, 0);
|
|
|
|
PROTECT(t, type);
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// `array` stores either
|
|
|
|
// 1. All the arguments to be passed to the bootstrap method in the case of `metafactory`
|
|
|
|
// 2. The vararg object array to be passed to `altMetafactory`
|
2015-08-06 23:22:14 +00:00
|
|
|
GcArray* array = makeArray(t, bootstrap->parameterCount());
|
|
|
|
PROTECT(t, array);
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// These are common arguments to metafactory and altMetafactory
|
2015-08-06 23:22:14 +00:00
|
|
|
unsigned argument = 0;
|
|
|
|
array->setBodyElement(t, argument++, lookup);
|
|
|
|
array->setBodyElement(t, argument++, name);
|
|
|
|
array->setBodyElement(t, argument++, type);
|
|
|
|
|
2016-12-07 17:23:13 +00:00
|
|
|
THREAD_RUNTIME_ARRAY(t, char, specBuffer, bootstrap->spec()->length());
|
|
|
|
|
2016-12-05 03:53:40 +00:00
|
|
|
const char* spec;
|
2017-01-19 17:27:08 +00:00
|
|
|
// `argArray` stores the final arguments to be passed to the bootstrap method.
|
|
|
|
// Later in this function we iterate through the method signature +
|
|
|
|
// bootstrap array and resolve the arguments as required into `array`.
|
|
|
|
//
|
|
|
|
// In the case of a `metafactory` call:
|
|
|
|
// `argArray = [caller, invokedName, invokedType, methodType, methodImplementation, instantiatedType]`
|
|
|
|
// `array = argArray`
|
|
|
|
//
|
|
|
|
// In the case of an `altMetafactory` call:
|
|
|
|
// `argArray = [caller, invokedName, invokedType, array]`
|
|
|
|
// `array = [methodType, methodImplementation, instantiatedType, flags, ...]`
|
2016-12-05 03:53:40 +00:00
|
|
|
GcArray* argArray = array;
|
|
|
|
PROTECT(t, argArray);
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// Check if the bootstrap method's signature matches that of an altMetafactory
|
2016-12-05 03:53:40 +00:00
|
|
|
if (::strcmp(reinterpret_cast<char*>(bootstrap->spec()->body().begin()),
|
|
|
|
"(Ljava/lang/invoke/MethodHandles$Lookup;"
|
|
|
|
"Ljava/lang/String;"
|
|
|
|
"Ljava/lang/invoke/MethodType;"
|
|
|
|
"[Ljava/lang/Object;)"
|
|
|
|
"Ljava/lang/invoke/CallSite;") == 0) {
|
2017-01-19 17:27:08 +00:00
|
|
|
// If so, create a new array to store the varargs in, and hardcode the BSM signature.
|
2016-12-05 03:53:40 +00:00
|
|
|
array = makeArray(t, bootstrapArray->length() - 1);
|
|
|
|
spec = "(Ljava/lang/invoke/MethodHandles$Lookup;"
|
|
|
|
"Ljava/lang/String;"
|
|
|
|
"Ljava/lang/invoke/MethodType;"
|
|
|
|
"Ljava/lang/invoke/MethodType;"
|
|
|
|
"Ljava/lang/invoke/MethodHandle;"
|
|
|
|
"Ljava/lang/invoke/MethodType;"
|
|
|
|
"I"
|
|
|
|
"I"
|
|
|
|
"[Ljava/lang/Class;"
|
|
|
|
"I"
|
|
|
|
"[Ljava/lang/invoke/MethodType;"
|
|
|
|
")Ljava/lang/invoke/CallSite;";
|
|
|
|
} else if (bootstrap->parameterCount() == 2 + bootstrapArray->length()) {
|
2017-01-19 17:27:08 +00:00
|
|
|
// We're calling the simpler `metafactory`. 2 + bootstrapArray->length() is the
|
|
|
|
// arguments to the bootstrap method (bootstrapArray->length() - 1), plus the 3 static
|
|
|
|
// arguments (lookup, name, type).
|
2016-12-07 17:23:13 +00:00
|
|
|
memcpy(RUNTIME_ARRAY_BODY(specBuffer),
|
|
|
|
bootstrap->spec()->body().begin(),
|
|
|
|
bootstrap->spec()->length());
|
|
|
|
spec = RUNTIME_ARRAY_BODY(specBuffer);
|
2016-12-05 03:53:40 +00:00
|
|
|
} else {
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
MethodSpecIterator it(t, spec);
|
2015-08-06 23:22:14 +00:00
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// Skip over the already handled 3 arguments.
|
2015-08-06 23:22:14 +00:00
|
|
|
for (unsigned i = 0; i < argument; ++i)
|
|
|
|
it.next();
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// If we're calling altMetafactory then we reset the argument
|
|
|
|
// offset, because we are filling the vararg array instead of the
|
|
|
|
// final argument array.
|
2016-12-05 03:53:40 +00:00
|
|
|
if (argArray != array) {
|
|
|
|
argument = 0;
|
|
|
|
}
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// `i` iterates through the bootstrap arguments (the +1 is because we skip
|
2017-09-06 09:48:26 +00:00
|
|
|
// the bootstrap method's name), `it` iterates through the corresponding types
|
2017-01-19 17:27:08 +00:00
|
|
|
// in the method signature
|
2015-08-06 23:22:14 +00:00
|
|
|
unsigned i = 0;
|
2016-12-05 03:53:40 +00:00
|
|
|
while (i + 1 < bootstrapArray->length() && it.hasNext()) {
|
2015-08-06 23:22:14 +00:00
|
|
|
const char* p = it.next();
|
2017-01-19 17:27:08 +00:00
|
|
|
|
2015-08-06 23:22:14 +00:00
|
|
|
switch (*p) {
|
|
|
|
case 'L': {
|
|
|
|
const char* const methodType = "Ljava/lang/invoke/MethodType;";
|
|
|
|
const char* const methodHandle = "Ljava/lang/invoke/MethodHandle;";
|
|
|
|
if (strncmp(p, methodType, strlen(methodType)) == 0) {
|
|
|
|
GcMethodType* type = makeMethodType(
|
|
|
|
t,
|
|
|
|
c->loader(),
|
|
|
|
cast<GcByteArray>(
|
|
|
|
t,
|
|
|
|
singletonObject(
|
|
|
|
t, invocation->pool(), bootstrapArray->body()[i + 1])),
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0);
|
|
|
|
|
|
|
|
array->setBodyElement(t, i + argument, type);
|
|
|
|
} else if (strncmp(p, methodHandle, strlen(methodHandle)) == 0) {
|
2017-07-10 16:01:56 +00:00
|
|
|
GcMethodHandle* handle = cast<GcMethodHandle>(t,
|
2015-08-06 23:22:14 +00:00
|
|
|
resolve(t,
|
|
|
|
c->loader(),
|
|
|
|
invocation->pool(),
|
|
|
|
bootstrapArray->body()[i + 1],
|
|
|
|
findMethodInClass,
|
|
|
|
GcNoSuchMethodError::Type));
|
|
|
|
|
|
|
|
array->setBodyElement(t, i + argument, handle);
|
|
|
|
} else {
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case 'I':
|
|
|
|
case 'F': {
|
|
|
|
GcInt* box = makeInt(
|
|
|
|
t,
|
|
|
|
singletonValue(t, invocation->pool(), bootstrapArray->body()[i + 1]));
|
|
|
|
|
|
|
|
array->setBodyElement(t, i + argument, box);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case 'J':
|
|
|
|
case 'D': {
|
|
|
|
uint64_t v;
|
|
|
|
memcpy(
|
|
|
|
&v,
|
|
|
|
&singletonValue(t, invocation->pool(), bootstrapArray->body()[i + 1]),
|
|
|
|
8);
|
|
|
|
|
|
|
|
GcLong* box = makeLong(t, v);
|
|
|
|
|
|
|
|
array->setBodyElement(t, i + argument, box);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default:
|
2017-07-10 16:01:56 +00:00
|
|
|
fprintf(stderr, "todo: unsupported bootstrap argument type: %s", p);
|
2015-08-06 23:22:14 +00:00
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
|
|
|
|
GcMethodHandle* handle
|
|
|
|
= (bootstrap->flags() & ACC_STATIC)
|
|
|
|
? 0
|
|
|
|
: makeMethodHandle(t, REF_invokeSpecial, c->loader(), bootstrap, 0);
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// If we're calling altMetafactory we set the fourth argument to the vararg array.
|
2016-12-05 03:53:40 +00:00
|
|
|
if (argArray != array) {
|
|
|
|
argArray->setBodyElement(t, 3, array);
|
|
|
|
}
|
|
|
|
|
2017-01-19 17:27:08 +00:00
|
|
|
// Finally we make the bootstrap call.
|
2015-08-06 23:22:14 +00:00
|
|
|
return cast<GcCallSite>(
|
2016-12-05 03:53:40 +00:00
|
|
|
t, t->m->processor->invokeArray(t, bootstrap, handle, argArray));
|
2015-08-06 23:22:14 +00:00
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
void noop()
|
|
|
|
{
|
|
|
|
}
|
2007-07-10 01:43:43 +00:00
|
|
|
|
2007-07-06 23:50:26 +00:00
|
|
|
#include "type-constructors.cpp"
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
} // namespace vm
|
2008-01-16 17:30:12 +00:00
|
|
|
|
|
|
|
// for debugging
|
2014-07-11 15:50:18 +00:00
|
|
|
AVIAN_EXPORT void vmfPrintTrace(Thread* t, FILE* out)
|
2008-01-16 17:30:12 +00:00
|
|
|
{
|
2014-07-11 15:50:18 +00:00
|
|
|
class Visitor : public Processor::StackVisitor {
|
2008-01-16 17:30:12 +00:00
|
|
|
public:
|
2014-07-11 15:50:18 +00:00
|
|
|
Visitor(Thread* t, FILE* out) : t(t), out(out)
|
|
|
|
{
|
|
|
|
}
|
2008-01-16 17:30:12 +00:00
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
virtual bool visit(Processor::StackWalker* walker)
|
|
|
|
{
|
2014-06-21 04:16:33 +00:00
|
|
|
const int8_t* class_ = walker->method()->class_()->name()->body().begin();
|
|
|
|
const int8_t* method = walker->method()->name()->body().begin();
|
2014-07-11 15:50:18 +00:00
|
|
|
int line = t->m->processor->lineNumber(t, walker->method(), walker->ip());
|
2008-01-16 17:30:12 +00:00
|
|
|
|
2013-04-09 23:45:19 +00:00
|
|
|
fprintf(out, " at %s.%s ", class_, method);
|
2008-01-16 17:30:12 +00:00
|
|
|
|
|
|
|
switch (line) {
|
|
|
|
case NativeLine:
|
2013-04-09 23:45:19 +00:00
|
|
|
fprintf(out, "(native)\n");
|
2008-01-16 17:30:12 +00:00
|
|
|
break;
|
|
|
|
case UnknownLine:
|
2013-04-09 23:45:19 +00:00
|
|
|
fprintf(out, "(unknown line)\n");
|
2008-01-16 17:30:12 +00:00
|
|
|
break;
|
|
|
|
default:
|
2013-04-09 23:45:19 +00:00
|
|
|
fprintf(out, "(line %d)\n", line);
|
2008-01-16 17:30:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
Thread* t;
|
2013-04-09 23:45:19 +00:00
|
|
|
FILE* out;
|
|
|
|
} v(t, out);
|
2008-01-16 17:30:12 +00:00
|
|
|
|
2013-04-09 23:45:19 +00:00
|
|
|
fprintf(out, "debug trace for thread %p\n", t);
|
2010-09-17 01:43:27 +00:00
|
|
|
|
2008-01-16 17:30:12 +00:00
|
|
|
t->m->processor->walkStack(t, &v);
|
2010-12-01 03:27:36 +00:00
|
|
|
|
2013-04-09 23:45:19 +00:00
|
|
|
fflush(out);
|
|
|
|
}
|
|
|
|
|
2014-07-11 15:50:18 +00:00
|
|
|
AVIAN_EXPORT void vmPrintTrace(Thread* t)
|
2013-04-09 23:45:19 +00:00
|
|
|
{
|
|
|
|
vmfPrintTrace(t, stderr);
|
2008-01-16 17:30:12 +00:00
|
|
|
}
|
2009-06-11 15:44:37 +00:00
|
|
|
|
|
|
|
// also for debugging
|
2014-07-11 15:47:57 +00:00
|
|
|
AVIAN_EXPORT void* vmAddressFromLine(GcMethod* m, unsigned line)
|
2009-06-11 15:44:37 +00:00
|
|
|
{
|
2014-06-29 05:48:17 +00:00
|
|
|
GcCode* code = m->code();
|
2010-09-17 01:43:27 +00:00
|
|
|
printf("code: %p\n", code);
|
2014-06-29 05:48:17 +00:00
|
|
|
GcLineNumberTable* lnt = code->lineNumberTable();
|
2010-09-17 01:43:27 +00:00
|
|
|
printf("lnt: %p\n", lnt);
|
2014-07-11 15:47:57 +00:00
|
|
|
|
2010-09-17 01:43:27 +00:00
|
|
|
if (lnt) {
|
|
|
|
unsigned last = 0;
|
|
|
|
unsigned bottom = 0;
|
2014-06-29 05:48:17 +00:00
|
|
|
unsigned top = lnt->length();
|
2014-07-11 15:50:18 +00:00
|
|
|
for (unsigned i = bottom; i < top; i++) {
|
2014-06-29 05:48:17 +00:00
|
|
|
uint64_t ln = lnt->body()[i];
|
2014-07-11 15:50:18 +00:00
|
|
|
if (lineNumberLine(ln) == line)
|
2010-09-17 01:43:27 +00:00
|
|
|
return reinterpret_cast<void*>(lineNumberIp(ln));
|
2014-07-11 15:50:18 +00:00
|
|
|
else if (lineNumberLine(ln) > line)
|
2010-09-17 01:43:27 +00:00
|
|
|
return reinterpret_cast<void*>(last);
|
|
|
|
last = lineNumberIp(ln);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2009-06-11 15:44:37 +00:00
|
|
|
}
|