mirror of
https://github.com/corda/corda.git
synced 2025-01-15 01:10:33 +00:00
progress towards thread support
This includes support for using the least significant bits of the class pointer to indicate object state, which we'll use to indicate the presence of a monitor pointer, among other things.
This commit is contained in:
parent
051e3bc7a8
commit
38cea04322
@ -5,7 +5,9 @@ public class TestExceptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void moreDangerous() {
|
private static void moreDangerous() {
|
||||||
evenMoreDangerous();
|
// synchronized (TestExceptions.class) {
|
||||||
|
evenMoreDangerous();
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void dangerous() {
|
private static void dangerous() {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
public class Test {
|
public class TestGC {
|
||||||
|
|
||||||
private static void small() {
|
private static void small() {
|
||||||
for (int i = 0; i < 1024; ++i) {
|
for (int i = 0; i < 1024; ++i) {
|
2
makefile
2
makefile
@ -127,7 +127,7 @@ fast-cflags = $(fast) $(cflags)
|
|||||||
classpath-sources = $(shell find $(classpath)/java -name '*.java')
|
classpath-sources = $(shell find $(classpath)/java -name '*.java')
|
||||||
classpath-classes = $(call java-classes,$(classpath-sources),$(classpath))
|
classpath-classes = $(call java-classes,$(classpath-sources),$(classpath))
|
||||||
|
|
||||||
input = $(bld)/classes/TestExceptions.class
|
input = $(bld)/classes/Test.class
|
||||||
input-depends = \
|
input-depends = \
|
||||||
$(classpath-classes) \
|
$(classpath-classes) \
|
||||||
$(jni-library)
|
$(jni-library)
|
||||||
|
10
src/common.h
10
src/common.h
@ -26,6 +26,9 @@ typedef void* object;
|
|||||||
const unsigned BytesPerWord = sizeof(uintptr_t);
|
const unsigned BytesPerWord = sizeof(uintptr_t);
|
||||||
const unsigned BitsPerWord = BytesPerWord * 8;
|
const unsigned BitsPerWord = BytesPerWord * 8;
|
||||||
|
|
||||||
|
const uintptr_t PointerMask
|
||||||
|
= ((~static_cast<uintptr_t>(0)) / BytesPerWord) * BytesPerWord;
|
||||||
|
|
||||||
const unsigned LikelyPageSizeInBytes = 4 * 1024;
|
const unsigned LikelyPageSizeInBytes = 4 * 1024;
|
||||||
|
|
||||||
inline unsigned
|
inline unsigned
|
||||||
@ -109,6 +112,13 @@ cast(object p, unsigned offset)
|
|||||||
return *reinterpret_cast<T*>(static_cast<uint8_t*>(p) + offset);
|
return *reinterpret_cast<T*>(static_cast<uint8_t*>(p) + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline T*
|
||||||
|
mask(T* p)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<T*>(reinterpret_cast<uintptr_t>(p) & PointerMask);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif//COMMON_H
|
#endif//COMMON_H
|
||||||
|
95
src/heap.cpp
95
src/heap.cpp
@ -26,6 +26,32 @@ System* system(Context*);
|
|||||||
void NO_RETURN abort(Context*);
|
void NO_RETURN abort(Context*);
|
||||||
void assert(Context*, bool);
|
void assert(Context*, bool);
|
||||||
|
|
||||||
|
inline object
|
||||||
|
get(object o, unsigned offsetInWords)
|
||||||
|
{
|
||||||
|
return mask(cast<object>(o, offsetInWords * BytesPerWord));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline object*
|
||||||
|
getp(object o, unsigned offsetInWords)
|
||||||
|
{
|
||||||
|
return &cast<object>(o, offsetInWords * BytesPerWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
set(object* o, object value)
|
||||||
|
{
|
||||||
|
*o = reinterpret_cast<object>
|
||||||
|
(reinterpret_cast<uintptr_t>(value)
|
||||||
|
| reinterpret_cast<uintptr_t>(*o) & (~PointerMask));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
set(object o, unsigned offsetInWords, object value)
|
||||||
|
{
|
||||||
|
set(getp(o, offsetInWords), value);
|
||||||
|
}
|
||||||
|
|
||||||
class Segment {
|
class Segment {
|
||||||
public:
|
public:
|
||||||
class Map {
|
class Map {
|
||||||
@ -662,7 +688,7 @@ fresh(Context* c, object o)
|
|||||||
inline bool
|
inline bool
|
||||||
wasCollected(Context* c, object o)
|
wasCollected(Context* c, object o)
|
||||||
{
|
{
|
||||||
return o and (not fresh(c, o)) and fresh(c, cast<object>(o, 0));
|
return o and (not fresh(c, o)) and fresh(c, get(o, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline object
|
inline object
|
||||||
@ -779,55 +805,55 @@ copy(Context* c, object o)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
update3(Context* c, object* p, bool* needsVisit)
|
update3(Context* c, object o, bool* needsVisit)
|
||||||
{
|
{
|
||||||
if (wasCollected(c, *p)) {
|
if (wasCollected(c, o)) {
|
||||||
*needsVisit = false;
|
*needsVisit = false;
|
||||||
return follow(c, *p);
|
return follow(c, o);
|
||||||
} else {
|
} else {
|
||||||
*needsVisit = true;
|
*needsVisit = true;
|
||||||
return copy(c, *p);
|
return copy(c, o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
update2(Context* c, object* p, bool* needsVisit)
|
update2(Context* c, object o, bool* needsVisit)
|
||||||
{
|
{
|
||||||
switch (c->mode) {
|
switch (c->mode) {
|
||||||
case MinorCollection:
|
case MinorCollection:
|
||||||
case OverflowCollection:
|
case OverflowCollection:
|
||||||
if (c->gen2.contains(*p)) {
|
if (c->gen2.contains(o)) {
|
||||||
*needsVisit = false;
|
*needsVisit = false;
|
||||||
return *p;
|
return o;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Gen2Collection:
|
case Gen2Collection:
|
||||||
if (c->gen2.contains(*p)) {
|
if (c->gen2.contains(o)) {
|
||||||
return update3(c, p, needsVisit);
|
return update3(c, o, needsVisit);
|
||||||
} else {
|
} else {
|
||||||
assert(c, c->nextGen1.contains(*p) or c->nextGen2.contains(*p));
|
assert(c, c->nextGen1.contains(o) or c->nextGen2.contains(o));
|
||||||
|
|
||||||
*needsVisit = false;
|
*needsVisit = false;
|
||||||
return *p;
|
return o;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return update3(c, p, needsVisit);
|
return update3(c, o, needsVisit);
|
||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
update(Context* c, object* p, bool* needsVisit)
|
update(Context* c, object* p, bool* needsVisit)
|
||||||
{
|
{
|
||||||
if (*p == 0) {
|
if (mask(*p) == 0) {
|
||||||
*needsVisit = false;
|
*needsVisit = false;
|
||||||
return *p;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
object r = update2(c, p, needsVisit);
|
object r = update2(c, mask(*p), needsVisit);
|
||||||
|
|
||||||
// update heap map.
|
// update heap map.
|
||||||
if (r) {
|
if (r) {
|
||||||
@ -956,22 +982,22 @@ bitsetNext(Context* c, uintptr_t* p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
collect(Context* c, void** p)
|
collect(Context* c, object* p)
|
||||||
{
|
{
|
||||||
object original = *p;
|
object original = mask(*p);
|
||||||
object parent = 0;
|
object parent = 0;
|
||||||
|
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf(stderr, "update %p (%s) at %p (%s)\n",
|
fprintf(stderr, "update %p (%s) at %p (%s)\n",
|
||||||
*p, segment(c, *p), p, segment(c, p));
|
mask(*p), segment(c, *p), p, segment(c, p));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsVisit;
|
bool needsVisit;
|
||||||
*p = update(c, p, &needsVisit);
|
set(p, update(c, mask(p), &needsVisit));
|
||||||
|
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf(stderr, " result: %p (%s) (visit? %d)\n",
|
fprintf(stderr, " result: %p (%s) (visit? %d)\n",
|
||||||
*p, segment(c, *p), needsVisit);
|
mask(*p), segment(c, *p), needsVisit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not needsVisit) return;
|
if (not needsVisit) return;
|
||||||
@ -995,17 +1021,16 @@ collect(Context* c, void** p)
|
|||||||
virtual bool visit(unsigned offset) {
|
virtual bool visit(unsigned offset) {
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf(stderr, " update %p (%s) at %p - offset %d from %p (%s)\n",
|
fprintf(stderr, " update %p (%s) at %p - offset %d from %p (%s)\n",
|
||||||
cast<object>(copy, offset * BytesPerWord),
|
get(copy, offset),
|
||||||
segment(c, cast<object>(copy, offset * BytesPerWord)),
|
segment(c, get(copy, offset)),
|
||||||
&cast<object>(copy, offset * BytesPerWord),
|
getp(copy, offset),
|
||||||
offset,
|
offset,
|
||||||
copy,
|
copy,
|
||||||
segment(c, copy));
|
segment(c, copy));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needsVisit;
|
bool needsVisit;
|
||||||
object childCopy = update
|
object childCopy = update(c, getp(copy, offset), &needsVisit);
|
||||||
(c, &cast<object>(copy, offset * BytesPerWord), &needsVisit);
|
|
||||||
|
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf(stderr, " result: %p (%s) (visit? %d)\n",
|
fprintf(stderr, " result: %p (%s) (visit? %d)\n",
|
||||||
@ -1027,7 +1052,7 @@ collect(Context* c, void** p)
|
|||||||
second = offset;
|
second = offset;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cast<object>(copy, offset * BytesPerWord) = childCopy;
|
set(copy, offset, childCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (visits > 1 and total > 2 and (second or needsVisit)) {
|
if (visits > 1 and total > 2 and (second or needsVisit)) {
|
||||||
@ -1070,8 +1095,8 @@ collect(Context* c, void** p)
|
|||||||
parent = original;
|
parent = original;
|
||||||
}
|
}
|
||||||
|
|
||||||
original = cast<object>(copy, walker.first * BytesPerWord);
|
original = get(copy, walker.first);
|
||||||
cast<object>(copy, walker.first * BytesPerWord) = follow(c, original);
|
set(copy, walker.first, follow(c, original));
|
||||||
goto visit;
|
goto visit;
|
||||||
} else {
|
} else {
|
||||||
// ascend
|
// ascend
|
||||||
@ -1131,16 +1156,16 @@ collect(Context* c, void** p)
|
|||||||
|
|
||||||
if (Debug) {
|
if (Debug) {
|
||||||
fprintf(stderr, " next is %p (%s) at %p - offset %d from %p (%s)\n",
|
fprintf(stderr, " next is %p (%s) at %p - offset %d from %p (%s)\n",
|
||||||
cast<object>(copy, walker.next * BytesPerWord),
|
get(copy, walker.next),
|
||||||
segment(c, cast<object>(copy, walker.next * BytesPerWord)),
|
segment(c, get(copy, walker.next)),
|
||||||
&cast<object>(copy, walker.next * BytesPerWord),
|
getp(copy, walker.next),
|
||||||
walker.next,
|
walker.next,
|
||||||
copy,
|
copy,
|
||||||
segment(c, copy));
|
segment(c, copy));
|
||||||
}
|
}
|
||||||
|
|
||||||
original = cast<object>(copy, walker.next * BytesPerWord);
|
original = get(copy, walker.next);
|
||||||
cast<object>(copy, walker.next * BytesPerWord) = follow(c, original);
|
set(copy, walker.next, follow(c, original));
|
||||||
goto visit;
|
goto visit;
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
@ -1236,7 +1261,7 @@ collect(Context* c, Segment* s, unsigned limit)
|
|||||||
Walker(Context* c, object p): c(c), p(p) { }
|
Walker(Context* c, object p): c(c), p(p) { }
|
||||||
|
|
||||||
virtual bool visit(unsigned offset) {
|
virtual bool visit(unsigned offset) {
|
||||||
collect(c, &cast<object>(p, offset * BytesPerWord));
|
collect(c, getp(p, offset));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
158
src/main.cpp
158
src/main.cpp
@ -1,8 +1,12 @@
|
|||||||
#include "sys/mman.h"
|
#include "sys/mman.h"
|
||||||
#include "sys/types.h"
|
#include "sys/types.h"
|
||||||
#include "sys/stat.h"
|
#include "sys/stat.h"
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
#include "fcntl.h"
|
#include "fcntl.h"
|
||||||
#include "dlfcn.h"
|
#include "dlfcn.h"
|
||||||
|
#include "errno.h"
|
||||||
|
#include "pthread.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
@ -86,6 +90,22 @@ dynamicCall(void* function, uint64_t* arguments, uint8_t* argumentTypes,
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
void*
|
||||||
|
run(void* t)
|
||||||
|
{
|
||||||
|
static_cast<vm::System::Thread*>(t)->run();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
now()
|
||||||
|
{
|
||||||
|
timeval tv = { 0, 0 };
|
||||||
|
gettimeofday(&tv, 0);
|
||||||
|
return (static_cast<int64_t>(tv.tv_sec) * 1000) +
|
||||||
|
(static_cast<int64_t>(tv.tv_usec) / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
append(vm::System* s, const char* a, const char* b, const char* c,
|
append(vm::System* s, const char* a, const char* b, const char* c,
|
||||||
const char* d)
|
const char* d)
|
||||||
@ -108,17 +128,95 @@ class System: public vm::System {
|
|||||||
public:
|
public:
|
||||||
class Monitor: public vm::System::Monitor {
|
class Monitor: public vm::System::Monitor {
|
||||||
public:
|
public:
|
||||||
Monitor(vm::System* s): s(s) { }
|
Monitor(vm::System* s): s(s), context(0), depth(0) {
|
||||||
|
pthread_mutex_init(&mutex, 0);
|
||||||
|
pthread_cond_init(&condition, 0);
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool tryAcquire(void*) { return true; }
|
virtual bool tryAcquire(void* context) {
|
||||||
virtual void acquire(void*) { }
|
if (this->context == context) {
|
||||||
virtual void release(void*) { }
|
++ depth;
|
||||||
virtual void wait(void*) { }
|
return true;
|
||||||
virtual void notify(void*) { }
|
} else {
|
||||||
virtual void notifyAll(void*) { }
|
switch (pthread_mutex_trylock(&mutex)) {
|
||||||
virtual void dispose() { s->free(this); }
|
case EBUSY:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
this->context = context;
|
||||||
|
++ depth;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
vm::abort(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void acquire(void* context) {
|
||||||
|
if (this->context != context) {
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
this->context = context;
|
||||||
|
}
|
||||||
|
++ depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void release(void* context) {
|
||||||
|
if (this->context == context) {
|
||||||
|
if (-- depth == 0) {
|
||||||
|
this->context = 0;
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vm::abort(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void wait(void* context, int64_t time) {
|
||||||
|
if (this->context == context) {
|
||||||
|
if (time) {
|
||||||
|
int64_t then = now() + time;
|
||||||
|
timespec ts = { then / 1000, (then % 1000) * 1000 * 1000 };
|
||||||
|
int rv = pthread_cond_timedwait(&condition, &mutex, &ts);
|
||||||
|
assert(s, rv == 0);
|
||||||
|
} else {
|
||||||
|
int rv = pthread_cond_wait(&condition, &mutex);
|
||||||
|
assert(s, rv == 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vm::abort(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void notify(void* context) {
|
||||||
|
if (this->context == context) {
|
||||||
|
int rv = pthread_cond_signal(&condition);
|
||||||
|
assert(s, rv == 0);
|
||||||
|
} else {
|
||||||
|
vm::abort(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void notifyAll(void* context) {
|
||||||
|
if (this->context == context) {
|
||||||
|
int rv = pthread_cond_broadcast(&condition);
|
||||||
|
assert(s, rv == 0);
|
||||||
|
} else {
|
||||||
|
vm::abort(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void dispose() {
|
||||||
|
pthread_mutex_destroy(&mutex);
|
||||||
|
pthread_cond_destroy(&condition);
|
||||||
|
s->free(this);
|
||||||
|
}
|
||||||
|
|
||||||
vm::System* s;
|
vm::System* s;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
pthread_cond_t condition;
|
||||||
|
void* context;
|
||||||
|
unsigned depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Library: public vm::System::Library {
|
class Library: public vm::System::Library {
|
||||||
@ -149,14 +247,20 @@ class System: public vm::System {
|
|||||||
vm::System::Library* next_;
|
vm::System::Library* next_;
|
||||||
};
|
};
|
||||||
|
|
||||||
System(unsigned limit): limit(limit), count(0) { }
|
System(unsigned limit): limit(limit), count(0) {
|
||||||
|
pthread_mutex_init(&mutex, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
~System() {
|
||||||
|
pthread_mutex_destroy(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool success(Status s) {
|
virtual bool success(Status s) {
|
||||||
return s == 0;
|
return s == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* tryAllocate(unsigned size) {
|
virtual void* tryAllocate(unsigned size) {
|
||||||
// todo: synchronize access
|
pthread_mutex_lock(&mutex);
|
||||||
|
|
||||||
if (Verbose) {
|
if (Verbose) {
|
||||||
fprintf(stderr, "try %d; count: %d; limit: %d\n",
|
fprintf(stderr, "try %d; count: %d; limit: %d\n",
|
||||||
@ -164,20 +268,26 @@ class System: public vm::System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (count + size > limit) {
|
if (count + size > limit) {
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
return 0;
|
return 0;
|
||||||
|
} else {
|
||||||
|
uintptr_t* up = static_cast<uintptr_t*>
|
||||||
|
(malloc(size + sizeof(uintptr_t)));
|
||||||
|
if (up == 0) {
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
vm::abort(this);
|
||||||
|
} else {
|
||||||
|
*up = size;
|
||||||
|
count += *up;
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
return up + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t* up = static_cast<uintptr_t*>(malloc(size + sizeof(uintptr_t)));
|
|
||||||
if (up == 0) abort();
|
|
||||||
|
|
||||||
*up = size;
|
|
||||||
count += *up;
|
|
||||||
|
|
||||||
return up + 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void free(const void* p) {
|
virtual void free(const void* p) {
|
||||||
// todo: synchronize access
|
pthread_mutex_lock(&mutex);
|
||||||
|
|
||||||
if (p) {
|
if (p) {
|
||||||
const uintptr_t* up = static_cast<const uintptr_t*>(p) - 1;
|
const uintptr_t* up = static_cast<const uintptr_t*>(p) - 1;
|
||||||
@ -193,10 +303,15 @@ class System: public vm::System {
|
|||||||
|
|
||||||
::free(const_cast<uintptr_t*>(up));
|
::free(const_cast<uintptr_t*>(up));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Status start(Thread*) {
|
virtual Status start(Thread* t) {
|
||||||
return 1;
|
pthread_t thread;
|
||||||
|
int rv = pthread_create(&thread, 0, run, t);
|
||||||
|
assert(this, rv == 0);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Status make(vm::System::Monitor** m) {
|
virtual Status make(vm::System::Monitor** m) {
|
||||||
@ -232,6 +347,7 @@ class System: public vm::System {
|
|||||||
::abort();
|
::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pthread_mutex_t mutex;
|
||||||
unsigned limit;
|
unsigned limit;
|
||||||
unsigned count;
|
unsigned count;
|
||||||
};
|
};
|
||||||
|
@ -21,7 +21,7 @@ class System {
|
|||||||
virtual bool tryAcquire(void* id) = 0;
|
virtual bool tryAcquire(void* id) = 0;
|
||||||
virtual void acquire(void* id) = 0;
|
virtual void acquire(void* id) = 0;
|
||||||
virtual void release(void* id) = 0;
|
virtual void release(void* id) = 0;
|
||||||
virtual void wait(void* id) = 0;
|
virtual void wait(void* id, int64_t time) = 0;
|
||||||
virtual void notify(void* id) = 0;
|
virtual void notify(void* id) = 0;
|
||||||
virtual void notifyAll(void* id) = 0;
|
virtual void notifyAll(void* id) = 0;
|
||||||
virtual void dispose() = 0;
|
virtual void dispose() = 0;
|
||||||
|
@ -995,7 +995,7 @@ writeSubtypeAssertions(Output* out, Object* o)
|
|||||||
{
|
{
|
||||||
for (Object* p = typeSubtypes(o); p; p = cdr(p)) {
|
for (Object* p = typeSubtypes(o); p; p = cdr(p)) {
|
||||||
Object* st = car(p);
|
Object* st = car(p);
|
||||||
out->write(" or objectClass(o) == arrayBodyUnsafe");
|
out->write(" or objectClass(t, o) == arrayBodyUnsafe");
|
||||||
out->write("(t, t->vm->types, Machine::");
|
out->write("(t, t->vm->types, Machine::");
|
||||||
out->write(capitalize(typeName(st)));
|
out->write(capitalize(typeName(st)));
|
||||||
out->write("Type)");
|
out->write("Type)");
|
||||||
@ -1035,8 +1035,8 @@ writeAccessor(Output* out, Object* member, Object* offset, bool unsafe = false)
|
|||||||
if (unsafe) {
|
if (unsafe) {
|
||||||
out->write(" assert(t, true);");
|
out->write(" assert(t, true);");
|
||||||
} else {
|
} else {
|
||||||
out->write(" assert(t, t->vm->unsafe or objectClass(o) == 0 or ");
|
out->write(" assert(t, t->vm->unsafe or ");
|
||||||
out->write("objectClass(o) == arrayBodyUnsafe");
|
out->write("objectClass(t, o) == arrayBodyUnsafe");
|
||||||
out->write("(t, t->vm->types, Machine::");
|
out->write("(t, t->vm->types, Machine::");
|
||||||
out->write(capitalize(::typeName(memberOwner(member))));
|
out->write(capitalize(::typeName(memberOwner(member))));
|
||||||
out->write("Type)");
|
out->write("Type)");
|
||||||
@ -1320,7 +1320,8 @@ writeConstructors(Output* out, Object* declarations)
|
|||||||
writeOffset(out, typeOffset(o), true);
|
writeOffset(out, typeOffset(o), true);
|
||||||
out->write(");\n");
|
out->write(");\n");
|
||||||
|
|
||||||
out->write(" objectClass(o) = arrayBody(t, t->vm->types, Machine::");
|
out->write(" cast<object>(o, 0) ");
|
||||||
|
out->write("= arrayBody(t, t->vm->types, Machine::");
|
||||||
out->write(capitalize(typeName(o)));
|
out->write(capitalize(typeName(o)));
|
||||||
out->write("Type);\n");
|
out->write("Type);\n");
|
||||||
|
|
||||||
@ -1538,7 +1539,7 @@ writeInitializations(Output* out, Object* declarations)
|
|||||||
out->write("t->vm->types = allocate(t, pad((");
|
out->write("t->vm->types = allocate(t, pad((");
|
||||||
out->write(count);
|
out->write(count);
|
||||||
out->write(" * sizeof(void*)) + 4 + sizeof(void*)));\n");
|
out->write(" * sizeof(void*)) + 4 + sizeof(void*)));\n");
|
||||||
out->write("objectClass(t->vm->types) = 0;\n");
|
out->write("cast<object>(t->vm->types, 0) = 0;\n");
|
||||||
out->write("arrayLength(t, t->vm->types) = ");
|
out->write("arrayLength(t, t->vm->types) = ");
|
||||||
out->write(count);
|
out->write(count);
|
||||||
out->write(";\n");
|
out->write(";\n");
|
||||||
|
101
src/vm.cpp
101
src/vm.cpp
@ -33,12 +33,6 @@ void set(Thread*, object&, object);
|
|||||||
object makeString(Thread*, const char*, ...);
|
object makeString(Thread*, const char*, ...);
|
||||||
object makeByteArray(Thread*, const char*, ...);
|
object makeByteArray(Thread*, const char*, ...);
|
||||||
|
|
||||||
object&
|
|
||||||
objectClass(object o)
|
|
||||||
{
|
|
||||||
return cast<object>(o, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum FieldCode {
|
enum FieldCode {
|
||||||
VoidField,
|
VoidField,
|
||||||
ByteField,
|
ByteField,
|
||||||
@ -163,6 +157,12 @@ class Thread : public JNIEnv {
|
|||||||
object heap[HeapSizeInWords];
|
object heap[HeapSizeInWords];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline object
|
||||||
|
objectClass(Thread*, object o)
|
||||||
|
{
|
||||||
|
return mask(cast<object>(o, 0));
|
||||||
|
}
|
||||||
|
|
||||||
#include "type-declarations.cpp"
|
#include "type-declarations.cpp"
|
||||||
#include "type-constructors.cpp"
|
#include "type-constructors.cpp"
|
||||||
|
|
||||||
@ -489,8 +489,8 @@ collect(Machine* m, Heap::CollectionType type)
|
|||||||
virtual unsigned sizeInWords(void* p) {
|
virtual unsigned sizeInWords(void* p) {
|
||||||
Thread* t = m->rootThread;
|
Thread* t = m->rootThread;
|
||||||
|
|
||||||
p = m->heap->follow(p);
|
p = m->heap->follow(mask(p));
|
||||||
object class_ = m->heap->follow(objectClass(p));
|
object class_ = m->heap->follow(objectClass(t, p));
|
||||||
|
|
||||||
unsigned n = divide(classFixedSize(t, class_), BytesPerWord);
|
unsigned n = divide(classFixedSize(t, class_), BytesPerWord);
|
||||||
|
|
||||||
@ -505,8 +505,8 @@ collect(Machine* m, Heap::CollectionType type)
|
|||||||
virtual void walk(void* p, Heap::Walker* w) {
|
virtual void walk(void* p, Heap::Walker* w) {
|
||||||
Thread* t = m->rootThread;
|
Thread* t = m->rootThread;
|
||||||
|
|
||||||
p = m->heap->follow(p);
|
p = m->heap->follow(mask(p));
|
||||||
object class_ = m->heap->follow(objectClass(p));
|
object class_ = m->heap->follow(objectClass(t, p));
|
||||||
object objectMask = m->heap->follow(classObjectMask(t, class_));
|
object objectMask = m->heap->follow(classObjectMask(t, class_));
|
||||||
|
|
||||||
if (objectMask) {
|
if (objectMask) {
|
||||||
@ -599,7 +599,7 @@ enter(Thread* t, Thread::State s)
|
|||||||
t->vm->exclusive = t;
|
t->vm->exclusive = t;
|
||||||
|
|
||||||
while (t->vm->activeCount > 1) {
|
while (t->vm->activeCount > 1) {
|
||||||
t->vm->stateLock->wait(t);
|
t->vm->stateLock->wait(t, 0);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -639,7 +639,7 @@ enter(Thread* t, Thread::State s)
|
|||||||
case Thread::NoState:
|
case Thread::NoState:
|
||||||
case Thread::IdleState: {
|
case Thread::IdleState: {
|
||||||
while (t->vm->exclusive) {
|
while (t->vm->exclusive) {
|
||||||
t->vm->stateLock->wait(t);
|
t->vm->stateLock->wait(t, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
++ t->vm->activeCount;
|
++ t->vm->activeCount;
|
||||||
@ -669,7 +669,7 @@ enter(Thread* t, Thread::State s)
|
|||||||
t->state = s;
|
t->state = s;
|
||||||
|
|
||||||
while (t->vm->liveCount > 1) {
|
while (t->vm->liveCount > 1) {
|
||||||
t->vm->stateLock->wait(t);
|
t->vm->stateLock->wait(t, 0);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -762,7 +762,7 @@ make(Thread* t, object class_)
|
|||||||
unsigned
|
unsigned
|
||||||
objectSize(Thread* t, object o)
|
objectSize(Thread* t, object o)
|
||||||
{
|
{
|
||||||
object class_ = objectClass(o);
|
object class_ = objectClass(t, o);
|
||||||
|
|
||||||
unsigned n = divide(classFixedSize(t, class_), BytesPerWord);
|
unsigned n = divide(classFixedSize(t, class_), BytesPerWord);
|
||||||
|
|
||||||
@ -921,8 +921,8 @@ makeUnsatisfiedLinkError(Thread* t, object message)
|
|||||||
inline bool
|
inline bool
|
||||||
isLongOrDouble(Thread* t, object o)
|
isLongOrDouble(Thread* t, object o)
|
||||||
{
|
{
|
||||||
return objectClass(o) == arrayBody(t, t->vm->types, Machine::LongType)
|
return objectClass(t, o) == arrayBody(t, t->vm->types, Machine::LongType)
|
||||||
or objectClass(o) == arrayBody(t, t->vm->types, Machine::DoubleType);
|
or objectClass(t, o) == arrayBody(t, t->vm->types, Machine::DoubleType);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
@ -1139,10 +1139,10 @@ instanceOf(Thread* t, object class_, object o)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (objectClass(class_)
|
if (objectClass(t, class_)
|
||||||
== arrayBody(t, t->vm->types, Machine::InterfaceType))
|
== arrayBody(t, t->vm->types, Machine::InterfaceType))
|
||||||
{
|
{
|
||||||
for (object oc = objectClass(o); oc; oc = classSuper(t, oc)) {
|
for (object oc = objectClass(t, o); oc; oc = classSuper(t, oc)) {
|
||||||
object itable = classInterfaceTable(t, oc);
|
object itable = classInterfaceTable(t, oc);
|
||||||
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
||||||
if (arrayBody(t, itable, i) == class_) {
|
if (arrayBody(t, itable, i) == class_) {
|
||||||
@ -1151,7 +1151,7 @@ instanceOf(Thread* t, object class_, object o)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (object oc = objectClass(o); oc; oc = classSuper(t, oc)) {
|
for (object oc = objectClass(t, o); oc; oc = classSuper(t, oc)) {
|
||||||
if (oc == class_) {
|
if (oc == class_) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1165,7 +1165,7 @@ object
|
|||||||
findInterfaceMethod(Thread* t, object method, object o)
|
findInterfaceMethod(Thread* t, object method, object o)
|
||||||
{
|
{
|
||||||
object interface = methodClass(t, method);
|
object interface = methodClass(t, method);
|
||||||
object itable = classInterfaceTable(t, objectClass(o));
|
object itable = classInterfaceTable(t, objectClass(t, o));
|
||||||
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
||||||
if (arrayBody(t, itable, i) == interface) {
|
if (arrayBody(t, itable, i) == interface) {
|
||||||
return arrayBody(t, arrayBody(t, itable, i + 1),
|
return arrayBody(t, arrayBody(t, itable, i + 1),
|
||||||
@ -1185,7 +1185,7 @@ findMethod(Thread* t, object method, object class_)
|
|||||||
inline object
|
inline object
|
||||||
findVirtualMethod(Thread* t, object method, object o)
|
findVirtualMethod(Thread* t, object method, object o)
|
||||||
{
|
{
|
||||||
return findMethod(t, method, objectClass(o));
|
return findMethod(t, method, objectClass(t, o));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -1336,7 +1336,8 @@ parsePool(Thread* t, Stream& s)
|
|||||||
|
|
||||||
for (unsigned i = 0; i < poolCount; ++i) {
|
for (unsigned i = 0; i < poolCount; ++i) {
|
||||||
object o = arrayBody(t, pool, i);
|
object o = arrayBody(t, pool, i);
|
||||||
if (objectClass(o) == arrayBody(t, t->vm->types, Machine::IntArrayType)) {
|
if (objectClass(t, o) == arrayBody(t, t->vm->types, Machine::IntArrayType))
|
||||||
|
{
|
||||||
switch (intArrayBody(t, o, 0)) {
|
switch (intArrayBody(t, o, 0)) {
|
||||||
case CONSTANT_Class: {
|
case CONSTANT_Class: {
|
||||||
set(t, arrayBody(t, pool, i),
|
set(t, arrayBody(t, pool, i),
|
||||||
@ -1361,7 +1362,8 @@ parsePool(Thread* t, Stream& s)
|
|||||||
|
|
||||||
for (unsigned i = 0; i < poolCount; ++i) {
|
for (unsigned i = 0; i < poolCount; ++i) {
|
||||||
object o = arrayBody(t, pool, i);
|
object o = arrayBody(t, pool, i);
|
||||||
if (objectClass(o) == arrayBody(t, t->vm->types, Machine::IntArrayType)) {
|
if (objectClass(t, o) == arrayBody(t, t->vm->types, Machine::IntArrayType))
|
||||||
|
{
|
||||||
switch (intArrayBody(t, o, 0)) {
|
switch (intArrayBody(t, o, 0)) {
|
||||||
case CONSTANT_Fieldref:
|
case CONSTANT_Fieldref:
|
||||||
case CONSTANT_Methodref:
|
case CONSTANT_Methodref:
|
||||||
@ -2064,7 +2066,8 @@ inline object
|
|||||||
resolveClass(Thread* t, object pool, unsigned index)
|
resolveClass(Thread* t, object pool, unsigned index)
|
||||||
{
|
{
|
||||||
object o = arrayBody(t, pool, index);
|
object o = arrayBody(t, pool, index);
|
||||||
if (objectClass(o) == arrayBody(t, t->vm->types, Machine::ByteArrayType)) {
|
if (objectClass(t, o) == arrayBody(t, t->vm->types, Machine::ByteArrayType))
|
||||||
|
{
|
||||||
PROTECT(t, pool);
|
PROTECT(t, pool);
|
||||||
|
|
||||||
o = resolveClass(t, o);
|
o = resolveClass(t, o);
|
||||||
@ -2079,7 +2082,8 @@ inline object
|
|||||||
resolveClass(Thread* t, object container, object& (*class_)(Thread*, object))
|
resolveClass(Thread* t, object container, object& (*class_)(Thread*, object))
|
||||||
{
|
{
|
||||||
object o = class_(t, container);
|
object o = class_(t, container);
|
||||||
if (objectClass(o) == arrayBody(t, t->vm->types, Machine::ByteArrayType)) {
|
if (objectClass(t, o) == arrayBody(t, t->vm->types, Machine::ByteArrayType))
|
||||||
|
{
|
||||||
PROTECT(t, container);
|
PROTECT(t, container);
|
||||||
|
|
||||||
o = resolveClass(t, o);
|
o = resolveClass(t, o);
|
||||||
@ -2095,7 +2099,8 @@ resolve(Thread* t, object pool, unsigned index,
|
|||||||
object (*find)(Thread*, object, object))
|
object (*find)(Thread*, object, object))
|
||||||
{
|
{
|
||||||
object o = arrayBody(t, pool, index);
|
object o = arrayBody(t, pool, index);
|
||||||
if (objectClass(o) == arrayBody(t, t->vm->types, Machine::ReferenceType)) {
|
if (objectClass(t, o) == arrayBody(t, t->vm->types, Machine::ReferenceType))
|
||||||
|
{
|
||||||
PROTECT(t, pool);
|
PROTECT(t, pool);
|
||||||
|
|
||||||
object class_ = resolveClass(t, o, referenceClass);
|
object class_ = resolveClass(t, o, referenceClass);
|
||||||
@ -2179,7 +2184,7 @@ makeNativeMethodData(Thread* t, object method, void* function, bool builtin)
|
|||||||
inline object
|
inline object
|
||||||
resolveNativeMethodData(Thread* t, object method)
|
resolveNativeMethodData(Thread* t, object method)
|
||||||
{
|
{
|
||||||
if (objectClass(methodCode(t, method))
|
if (objectClass(t, methodCode(t, method))
|
||||||
== arrayBody(t, t->vm->types, Machine::ByteArrayType))
|
== arrayBody(t, t->vm->types, Machine::ByteArrayType))
|
||||||
{
|
{
|
||||||
object data = 0;
|
object data = 0;
|
||||||
@ -2333,7 +2338,7 @@ toString(JNIEnv* e, jobject this_)
|
|||||||
|
|
||||||
object s = makeString
|
object s = makeString
|
||||||
(t, "%s@%p",
|
(t, "%s@%p",
|
||||||
&byteArrayBody(t, className(t, objectClass(*this_)), 0),
|
&byteArrayBody(t, className(t, objectClass(t, *this_)), 0),
|
||||||
*this_);
|
*this_);
|
||||||
|
|
||||||
pushSafe(t, s);
|
pushSafe(t, s);
|
||||||
@ -2493,13 +2498,13 @@ Thread::Thread(Machine* m):
|
|||||||
#include "type-initializations.cpp"
|
#include "type-initializations.cpp"
|
||||||
|
|
||||||
object arrayClass = arrayBody(t, t->vm->types, Machine::ArrayType);
|
object arrayClass = arrayBody(t, t->vm->types, Machine::ArrayType);
|
||||||
set(t, objectClass(t->vm->types), arrayClass);
|
set(t, cast<object>(t->vm->types, 0), arrayClass);
|
||||||
|
|
||||||
object classClass = arrayBody(t, m->types, Machine::ClassType);
|
object classClass = arrayBody(t, m->types, Machine::ClassType);
|
||||||
set(t, objectClass(classClass), classClass);
|
set(t, cast<object>(classClass, 0), classClass);
|
||||||
|
|
||||||
object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType);
|
object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType);
|
||||||
set(t, objectClass(intArrayClass), classClass);
|
set(t, cast<object>(intArrayClass, 0), classClass);
|
||||||
|
|
||||||
m->unsafe = false;
|
m->unsafe = false;
|
||||||
|
|
||||||
@ -2668,7 +2673,7 @@ run(Thread* t)
|
|||||||
case arraylength: {
|
case arraylength: {
|
||||||
object array = pop(t);
|
object array = pop(t);
|
||||||
if (LIKELY(array)) {
|
if (LIKELY(array)) {
|
||||||
if (objectClass(array)
|
if (objectClass(t, array)
|
||||||
== arrayBody(t, t->vm->types, Machine::ObjectArrayType))
|
== arrayBody(t, t->vm->types, Machine::ObjectArrayType))
|
||||||
{
|
{
|
||||||
push(t, makeInt(t, objectArrayLength(t, array)));
|
push(t, makeInt(t, objectArrayLength(t, array)));
|
||||||
@ -2832,7 +2837,7 @@ run(Thread* t)
|
|||||||
if (not instanceOf(t, class_, stack[sp - 1])) {
|
if (not instanceOf(t, class_, stack[sp - 1])) {
|
||||||
object message = makeString
|
object message = makeString
|
||||||
(t, "%s as %s",
|
(t, "%s as %s",
|
||||||
&byteArrayBody(t, className(t, objectClass(stack[sp - 1])), 0),
|
&byteArrayBody(t, className(t, objectClass(t, stack[sp - 1])), 0),
|
||||||
&byteArrayBody(t, className(t, class_), 0));
|
&byteArrayBody(t, className(t, class_), 0));
|
||||||
exception = makeClassCastException(t, message);
|
exception = makeClassCastException(t, message);
|
||||||
goto throw_;
|
goto throw_;
|
||||||
@ -3639,6 +3644,26 @@ run(Thread* t)
|
|||||||
push(t, makeLong(t, longValue(t, a) ^ longValue(t, b)));
|
push(t, makeLong(t, longValue(t, a) ^ longValue(t, b)));
|
||||||
} goto loop;
|
} goto loop;
|
||||||
|
|
||||||
|
// case monitorenter: {
|
||||||
|
// object o = pop(t);
|
||||||
|
// if (LIKELY(o)) {
|
||||||
|
// objectMonitor(t, o)->acquire(t);
|
||||||
|
// } else {
|
||||||
|
// exception = makeNullPointerException(t);
|
||||||
|
// goto throw_;
|
||||||
|
// }
|
||||||
|
// } goto loop;
|
||||||
|
|
||||||
|
// case monitorexit: {
|
||||||
|
// object o = pop(t);
|
||||||
|
// if (LIKELY(o)) {
|
||||||
|
// objectMonitor(t, o)->release(t);
|
||||||
|
// } else {
|
||||||
|
// exception = makeNullPointerException(t);
|
||||||
|
// goto throw_;
|
||||||
|
// }
|
||||||
|
// } goto loop;
|
||||||
|
|
||||||
case new_: {
|
case new_: {
|
||||||
uint8_t index1 = codeBody(t, code, ip++);
|
uint8_t index1 = codeBody(t, code, ip++);
|
||||||
uint8_t index2 = codeBody(t, code, ip++);
|
uint8_t index2 = codeBody(t, code, ip++);
|
||||||
@ -3948,7 +3973,7 @@ run(Thread* t)
|
|||||||
arrayBody(t, codePool(t, code), exceptionHandlerCatchType(eh) - 1);
|
arrayBody(t, codePool(t, code), exceptionHandlerCatchType(eh) - 1);
|
||||||
|
|
||||||
if (catchType == 0 or
|
if (catchType == 0 or
|
||||||
(objectClass(catchType)
|
(objectClass(t, catchType)
|
||||||
== arrayBody(t, t->vm->types, Machine::ClassType) and
|
== arrayBody(t, t->vm->types, Machine::ClassType) and
|
||||||
instanceOf(t, catchType, exception)))
|
instanceOf(t, catchType, exception)))
|
||||||
{
|
{
|
||||||
@ -3970,7 +3995,7 @@ run(Thread* t)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "%s", &byteArrayBody
|
fprintf(stderr, "%s", &byteArrayBody
|
||||||
(t, className(t, objectClass(exception)), 0));
|
(t, className(t, objectClass(t, exception)), 0));
|
||||||
|
|
||||||
if (throwableMessage(t, exception)) {
|
if (throwableMessage(t, exception)) {
|
||||||
object m = throwableMessage(t, exception);
|
object m = throwableMessage(t, exception);
|
||||||
@ -3994,17 +4019,17 @@ run(Thread* t)
|
|||||||
int line = lineNumber
|
int line = lineNumber
|
||||||
(t, stackTraceElementMethod(t, e), stackTraceElementIp(t, e));
|
(t, stackTraceElementMethod(t, e), stackTraceElementIp(t, e));
|
||||||
|
|
||||||
fprintf(stderr, " at %s.%s", class_, method);
|
fprintf(stderr, " at %s.%s ", class_, method);
|
||||||
|
|
||||||
switch (line) {
|
switch (line) {
|
||||||
case NativeLine:
|
case NativeLine:
|
||||||
fprintf(stderr, "(native)\n");
|
fprintf(stderr, "(native)\n");
|
||||||
break;
|
break;
|
||||||
case UnknownLine:
|
case UnknownLine:
|
||||||
fprintf(stderr, "(unknown)\n");
|
fprintf(stderr, "(unknown line)\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "(%d)\n", line);
|
fprintf(stderr, "(line %d)\n", line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user