factor a lot of code out of vm.cpp, since it was becoming unwieldy

This commit is contained in:
Joel Dice 2007-07-06 09:24:06 -06:00
parent 6678d31d5c
commit 427dbedd0f
8 changed files with 1343 additions and 1261 deletions

View File

@ -63,9 +63,14 @@ interpreter-depends = \
$(src)/class-finder.h \
$(src)/stream.h \
$(src)/constants.h \
$(src)/vm.h
$(src)/vm.h \
$(src)/vm-jni.h \
$(src)/vm-builtin.h \
$(src)/vm-declarations.h
interpreter-sources = \
$(src)/vm.cpp \
$(src)/vm-jni.cpp \
$(src)/vm-builtin.cpp \
$(src)/heap.cpp \
$(src)/main.cpp

View File

@ -1479,7 +1479,7 @@ writeInitialization(Output* out, Object* type)
if (typeObjectMask(type) != 1) {
out->write(" PROTECT(t, mask);\n");
}
out->write(" object name = makeByteArray(t, \"");
out->write(" object name = ::makeByteArray(t, \"");
out->write(typeJavaName(type));
out->write("\");\n");

97
src/vm-builtin.cpp Normal file
View File

@ -0,0 +1,97 @@
#include "vm-builtin.h"
namespace vm {
namespace builtin {
void
loadLibrary(JNIEnv* e, jstring nameString)
{
Thread* t = static_cast<Thread*>(e);
if (LIKELY(nameString)) {
object n = *nameString;
char name[stringLength(t, n) + 1];
memcpy(name,
&byteArrayBody(t, stringBytes(t, n), stringOffset(t, n)),
stringLength(t, n));
name[stringLength(t, n)] = 0;
System::Library* lib;
if (LIKELY(t->vm->system->success
(t->vm->system->load(&lib, name, t->vm->libraries))))
{
t->vm->libraries = lib;
} else {
object message = makeString(t, "library not found: %s", name);
t->exception = makeRuntimeException(t, message);
}
} else {
t->exception = makeNullPointerException(t);
}
}
jstring
toString(JNIEnv* e, jobject this_)
{
Thread* t = static_cast<Thread*>(e);
object s = makeString
(t, "%s@%p",
&byteArrayBody(t, className(t, objectClass(t, *this_)), 0),
*this_);
return pushReference(t, s);
}
jarray
trace(JNIEnv* e, jint skipCount)
{
Thread* t = static_cast<Thread*>(e);
int frame = t->frame;
while (skipCount-- and frame >= 0) {
frame = frameNext(t, frame);
}
if (methodClass(t, frameMethod(t, frame))
== arrayBody(t, t->vm->types, Machine::ThrowableType))
{
// skip Throwable constructors
while (strcmp(reinterpret_cast<const int8_t*>("<init>"),
&byteArrayBody(t, methodName(t, frameMethod(t, frame)), 0))
== 0)
{
frame = frameNext(t, frame);
}
}
return pushReference(t, makeTrace(t, frame));
}
void
populate(Thread* t, object map)
{
struct {
const char* key;
void* value;
} builtins[] = {
{ "Java_java_lang_Object_toString",
reinterpret_cast<void*>(toString) },
{ "Java_java_lang_System_loadLibrary",
reinterpret_cast<void*>(loadLibrary) },
{ "Java_java_lang_Throwable_trace",
reinterpret_cast<void*>(trace) },
{ 0, 0 }
};
for (unsigned i = 0; builtins[i].key; ++i) {
object key = makeByteArray(t, builtins[i].key);
PROTECT(t, key);
object value = makePointer(t, builtins[i].value);
hashMapInsert(t, map, key, value, byteArrayHash);
}
}
} // namespace builtin
} // namespace vm

15
src/vm-builtin.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef VM_BUITLIN_H
#define VM_BUITLIN_H
#include "vm-declarations.h"
namespace vm {
namespace builtin {
void
populate(Thread* t, object map);
} // namespace builtin
} // namespace vm
#endif//VM_BUILTIN_H

View File

@ -1,15 +1,67 @@
#ifndef JNI_VM_H
#define JNI_VM_H
#ifndef VM_DECLARATIONS_H
#define VM_DECLARATIONS_H
#include "stdint.h"
#include "stdarg.h"
#include "common.h"
#include "system.h"
#include "heap.h"
#include "class-finder.h"
#define JNIEXPORT
#define JNIIMPORT
#define JNIEXPORT __attribute__ ((visibility("default")))
#define JNIIMPORT __attribute__ ((visibility("hidden")))
#define JNICALL
#define PROTECT(thread, name) \
Thread::Protector MAKE_NAME(protector_) (thread, &name);
#define ACQUIRE(t, x) MonitorResource MAKE_NAME(monitorResource_) (t, x)
#define ACQUIRE_RAW(t, x) RawMonitorResource MAKE_NAME(monitorResource_) (t, x)
#define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state)
namespace vm {
const bool Verbose = false;
const bool Debug = false;
const bool DebugRun = false;
const bool DebugStack = false;
const uintptr_t HashTakenMark = 1;
const uintptr_t ExtendedMark = 2;
const unsigned FrameBaseOffset = 0;
const unsigned FrameNextOffset = 1;
const unsigned FrameMethodOffset = 2;
const unsigned FrameIpOffset = 3;
const unsigned FrameFootprint = 4;
enum FieldCode {
VoidField,
ByteField,
CharField,
DoubleField,
FloatField,
IntField,
LongField,
ShortField,
BooleanField,
ObjectField
};
enum StackTag {
IntTag, // must be zero
ObjectTag
};
const int NativeLine = -1;
const int UnknownLine = -2;
const unsigned WeakReferenceFlag = 1 << 0;
class Thread;
typedef Thread JNIEnv;
typedef uint8_t jboolean;
typedef int8_t jbyte;
typedef uint16_t jchar;
@ -94,14 +146,6 @@ struct JavaVMVTable {
(JavaVM*, void**, void*);
};
struct JNIEnvVTable;
struct JNIEnv {
JNIEnv(JNIEnvVTable* vtable): vtable(vtable) { }
JNIEnvVTable* vtable;
};
struct JNIEnvVTable {
void* reserved0;
void* reserved1;
@ -1025,6 +1069,687 @@ struct JNIEnvVTable {
(JNIEnv*, jobject);
};
inline int
strcmp(const int8_t* a, const int8_t* b)
{
return ::strcmp(reinterpret_cast<const char*>(a),
reinterpret_cast<const char*>(b));
}
class Machine {
public:
enum {
#include "type-enums.cpp"
} Type;
Machine(System* system, Heap* heap, ClassFinder* classFinder);
~Machine() {
dispose();
}
void dispose();
System* system;
Heap* heap;
ClassFinder* classFinder;
Thread* rootThread;
Thread* exclusive;
unsigned activeCount;
unsigned liveCount;
System::Monitor* stateLock;
System::Monitor* heapLock;
System::Monitor* classLock;
System::Monitor* finalizerLock;
System::Library* libraries;
object classMap;
object bootstrapClassMap;
object builtinMap;
object monitorMap;
object types;
object finalizers;
object doomed;
object weakReferences;
bool unsafe;
JNIEnvVTable jniEnvVTable;
};
class Chain {
public:
Chain(Chain* next): next(next) { }
static unsigned footprint(unsigned sizeInBytes) {
return sizeof(Chain) + sizeInBytes;
}
uint8_t* data() {
return reinterpret_cast<uint8_t*>(this) + sizeof(Chain);
}
static void dispose(System* s, Chain* c) {
if (c) {
if (c->next) dispose(s, c->next);
s->free(c);
}
}
Chain* next;
};
class Thread {
public:
enum State {
NoState,
ActiveState,
IdleState,
ZombieState,
ExclusiveState,
ExitState
};
class Protector {
public:
Protector(Thread* t, object* p): t(t), p(p), next(t->protector) {
t->protector = this;
}
~Protector() {
t->protector = next;
}
Thread* t;
object* p;
Protector* next;
};
static const unsigned HeapSizeInBytes = 64 * 1024;
static const unsigned StackSizeInBytes = 64 * 1024;
static const unsigned HeapSizeInWords = HeapSizeInBytes / BytesPerWord;
static const unsigned StackSizeInWords = StackSizeInBytes / BytesPerWord;
Thread(Machine* m);
void dispose();
JNIEnvVTable* vtable;
Machine* vm;
Thread* next;
Thread* child;
State state;
object thread;
object code;
object exception;
unsigned ip;
unsigned sp;
int frame;
unsigned heapIndex;
Protector* protector;
Chain* chain;
uintptr_t stack[StackSizeInWords];
object heap[HeapSizeInWords];
};
inline object
objectClass(Thread*, object o)
{
return mask(cast<object>(o, 0));
}
void enter(Thread* t, Thread::State state);
class StateResource {
public:
StateResource(Thread* t, Thread::State state): t(t), oldState(t->state) {
enter(t, state);
}
~StateResource() { enter(t, oldState); }
private:
Thread* t;
Thread::State oldState;
};
class MonitorResource {
public:
MonitorResource(Thread* t, System::Monitor* m): t(t), m(m) {
if (not m->tryAcquire(t)) {
ENTER(t, Thread::IdleState);
m->acquire(t);
}
}
~MonitorResource() { m->release(t); }
private:
Thread* t;
System::Monitor* m;
};
class RawMonitorResource {
public:
RawMonitorResource(Thread* t, System::Monitor* m): t(t), m(m) {
m->acquire(t);
}
~RawMonitorResource() { m->release(t); }
private:
Thread* t;
System::Monitor* m;
};
inline void NO_RETURN
abort(Thread* t)
{
abort(t->vm->system);
}
inline void
assert(Thread* t, bool v)
{
assert(t->vm->system, v);
}
inline void
expect(Thread* t, bool v)
{
expect(t->vm->system, v);
}
inline object
allocateLarge(Thread* t, unsigned sizeInBytes)
{
void* p = t->vm->system->allocate(Chain::footprint(sizeInBytes));
t->chain = new (p) Chain(t->chain);
return t->chain->data();
}
inline object
allocateSmall(Thread* t, unsigned sizeInBytes)
{
object o = t->heap + t->heapIndex;
t->heapIndex += divide(sizeInBytes, BytesPerWord);
return o;
}
object
allocate2(Thread* t, unsigned sizeInBytes);
inline object
allocate(Thread* t, unsigned sizeInBytes)
{
if (UNLIKELY(t->heapIndex + divide(sizeInBytes, BytesPerWord)
>= Thread::HeapSizeInWords
or t->vm->exclusive))
{
return allocate2(t, sizeInBytes);
} else {
return allocateSmall(t, sizeInBytes);
}
}
inline void
set(Thread* t, object& target, object value)
{
target = value;
if (t->vm->heap->needsMark(&target)) {
ACQUIRE_RAW(t, t->vm->heapLock);
t->vm->heap->mark(&target);
}
}
object&
arrayBodyUnsafe(Thread*, object, unsigned);
#include "type-declarations.cpp"
object
makeTrace(Thread* t, int frame);
object
makeTrace(Thread* t);
inline object
makeRuntimeException(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeRuntimeException(t, message, trace, 0);
}
inline object
makeArrayIndexOutOfBoundsException(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeArrayIndexOutOfBoundsException(t, message, trace, 0);
}
inline object
makeNegativeArrayStoreException(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeNegativeArrayStoreException(t, message, trace, 0);
}
inline object
makeClassCastException(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeClassCastException(t, message, trace, 0);
}
inline object
makeClassNotFoundException(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeClassNotFoundException(t, message, trace, 0);
}
inline object
makeNullPointerException(Thread* t)
{
return makeNullPointerException(t, 0, makeTrace(t), 0);
}
inline object
makeStackOverflowError(Thread* t)
{
return makeStackOverflowError(t, 0, makeTrace(t), 0);
}
inline object
makeNoSuchFieldError(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeNoSuchFieldError(t, message, trace, 0);
}
inline object
makeNoSuchMethodError(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeNoSuchMethodError(t, message, trace, 0);
}
inline object
makeUnsatisfiedLinkError(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeUnsatisfiedLinkError(t, message, trace, 0);
}
object
makeByteArray(Thread* t, const char* format, ...);
object
makeString(Thread* t, const char* format, ...);
inline void
pushObject(Thread* t, object o)
{
if (DebugStack) {
fprintf(stderr, "push object %p at %d\n", o, t->sp);
}
assert(t, t->sp + 1 < Thread::StackSizeInWords / 2);
t->stack[(t->sp * 2) ] = ObjectTag;
t->stack[(t->sp * 2) + 1] = reinterpret_cast<uintptr_t>(o);
++ t->sp;
}
inline void
pushInt(Thread* t, uint32_t v)
{
if (DebugStack) {
fprintf(stderr, "push int %d at %d\n", v, t->sp);
}
assert(t, t->sp + 1 < Thread::StackSizeInWords / 2);
t->stack[(t->sp * 2) ] = IntTag;
t->stack[(t->sp * 2) + 1] = v;
++ t->sp;
}
inline void
pushLong(Thread* t, uint64_t v)
{
if (DebugStack) {
fprintf(stderr, "push long " LLD " at %d\n", v, t->sp);
}
pushInt(t, v >> 32);
pushInt(t, v & 0xFF);
}
inline object
popObject(Thread* t)
{
if (DebugStack) {
fprintf(stderr, "pop object %p at %d\n",
reinterpret_cast<object>(t->stack[((t->sp - 1) * 2) + 1]),
t->sp - 1);
}
assert(t, t->stack[(t->sp - 1) * 2] == ObjectTag);
return reinterpret_cast<object>(t->stack[((-- t->sp) * 2) + 1]);
}
inline uint32_t
popInt(Thread* t)
{
if (DebugStack) {
fprintf(stderr, "pop int " LD " at %d\n",
t->stack[((t->sp - 1) * 2) + 1],
t->sp - 1);
}
assert(t, t->stack[(t->sp - 1) * 2] == IntTag);
return t->stack[((-- t->sp) * 2) + 1];
}
inline uint64_t
popLong(Thread* t)
{
if (DebugStack) {
fprintf(stderr, "pop long " LLD " at %d\n",
(static_cast<uint64_t>(t->stack[((t->sp - 2) * 2) + 1]) << 32)
| static_cast<uint64_t>(t->stack[((t->sp - 1) * 2) + 1]),
t->sp - 2);
}
uint64_t a = popInt(t);
uint64_t b = popInt(t);
return (b << 32) | a;
}
inline object
peekObject(Thread* t, unsigned index)
{
if (DebugStack) {
fprintf(stderr, "peek object %p at %d\n",
reinterpret_cast<object>(t->stack[(index * 2) + 1]),
index);
}
assert(t, index < Thread::StackSizeInWords / 2);
assert(t, t->stack[index * 2] == ObjectTag);
return *reinterpret_cast<object*>(t->stack + (index * 2) + 1);
}
inline uint32_t
peekInt(Thread* t, unsigned index)
{
if (DebugStack) {
fprintf(stderr, "peek int " LD " at %d\n",
t->stack[(index * 2) + 1],
index);
}
assert(t, index < Thread::StackSizeInWords / 2);
assert(t, t->stack[index * 2] == IntTag);
return t->stack[(index * 2) + 1];
}
inline uint64_t
peekLong(Thread* t, unsigned index)
{
if (DebugStack) {
fprintf(stderr, "peek long " LLD " at %d\n",
(static_cast<uint64_t>(t->stack[(index * 2) + 1]) << 32)
| static_cast<uint64_t>(t->stack[((index + 1) * 2) + 1]),
index);
}
return (static_cast<uint64_t>(peekInt(t, index)) << 32)
| static_cast<uint64_t>(peekInt(t, index + 1));
}
inline void
pokeObject(Thread* t, unsigned index, object value)
{
if (DebugStack) {
fprintf(stderr, "poke object %p at %d\n", value, index);
}
t->stack[index * 2] = ObjectTag;
t->stack[(index * 2) + 1] = reinterpret_cast<uintptr_t>(value);
}
inline void
pokeInt(Thread* t, unsigned index, uint32_t value)
{
if (DebugStack) {
fprintf(stderr, "poke int %d at %d\n", value, index);
}
t->stack[index * 2] = IntTag;
t->stack[(index * 2) + 1] = value;
}
inline void
pokeLong(Thread* t, unsigned index, uint64_t value)
{
if (DebugStack) {
fprintf(stderr, "poke long " LLD " at %d\n", value, index);
}
pokeInt(t, index, value >> 32);
pokeInt(t, index + 2, value & 0xFF);
}
inline object*
pushReference(Thread* t, object o)
{
expect(t, t->sp + 1 < Thread::StackSizeInWords / 2);
pushObject(t, o);
return reinterpret_cast<object*>(t->stack + ((t->sp - 1) * 2) + 1);
}
inline int
frameNext(Thread* t, int frame)
{
return peekInt(t, frame + FrameNextOffset);
}
inline object
frameMethod(Thread* t, int frame)
{
return peekObject(t, frame + FrameMethodOffset);
}
inline unsigned
frameIp(Thread* t, int frame)
{
return peekInt(t, frame + FrameIpOffset);
}
inline unsigned
frameBase(Thread* t, int frame)
{
return peekInt(t, frame + FrameBaseOffset);
}
inline object
makeTrace(Thread* t)
{
pokeInt(t, t->frame + FrameIpOffset, t->ip);
return makeTrace(t, t->frame);
}
inline uint32_t
hash(const int8_t* s, unsigned length)
{
uint32_t h = 0;
for (unsigned i = 0; i < length; ++i) h = (h * 31) + s[i];
return h;
}
inline unsigned
baseSize(Thread* t, object o, object class_)
{
return divide(classFixedSize(t, class_), BytesPerWord)
+ divide(classArrayElementSize(t, class_)
* cast<uint32_t>(o, classFixedSize(t, class_) - 4),
BytesPerWord);
}
inline bool
objectExtended(Thread*, object o)
{
return (cast<uintptr_t>(o, 0) & (~PointerMask)) == ExtendedMark;
}
inline uintptr_t&
extendedWord(Thread* t, object o, unsigned baseSize)
{
assert(t, objectExtended(t, o));
return cast<uintptr_t>(o, baseSize * BytesPerWord);
}
inline unsigned
extendedSize(Thread* t, object o, unsigned baseSize)
{
return baseSize + objectExtended(t, o);
}
inline bool
hashTaken(Thread*, object o)
{
return (cast<uintptr_t>(o, 0) & (~PointerMask)) == HashTakenMark;
}
inline void
markHashTaken(Thread* t, object o)
{
assert(t, not objectExtended(t, o));
cast<uintptr_t>(o, 0) |= HashTakenMark;
}
inline uint32_t
takeHash(Thread*, object o)
{
return reinterpret_cast<uintptr_t>(o) / BytesPerWord;
}
inline uint32_t
objectHash(Thread* t, object o)
{
if (objectExtended(t, o)) {
return extendedWord(t, o, baseSize(t, o, objectClass(t, o)));
} else {
markHashTaken(t, o);
return takeHash(t, o);
}
}
inline bool
objectEqual(Thread*, object a, object b)
{
return a == b;
}
inline uint32_t
referenceHash(Thread* t, object o)
{
return objectHash(t, jreferenceTarget(t, o));
}
inline bool
referenceEqual(Thread* t, object a, object b)
{
return a == jreferenceTarget(t, b);
}
inline uint32_t
byteArrayHash(Thread* t, object array)
{
return hash(&byteArrayBody(t, array, 0), byteArrayLength(t, array));
}
inline bool
byteArrayEqual(Thread* t, object a, object b)
{
return a == b or
((byteArrayLength(t, a) == byteArrayLength(t, b)) and
memcmp(&byteArrayBody(t, a, 0), &byteArrayBody(t, b, 0),
byteArrayLength(t, a)) == 0);
}
inline bool
intArrayEqual(Thread* t, object a, object b)
{
return a == b or
((intArrayLength(t, a) == intArrayLength(t, b)) and
memcmp(&intArrayBody(t, a, 0), &intArrayBody(t, b, 0),
intArrayLength(t, a) * 4) == 0);
}
inline uint32_t
methodHash(Thread* t, object method)
{
return byteArrayHash(t, methodName(t, method))
^ byteArrayHash(t, methodSpec(t, method));
}
inline bool
methodEqual(Thread* t, object a, object b)
{
return a == b or
(byteArrayEqual(t, methodName(t, a), methodName(t, b)) and
byteArrayEqual(t, methodSpec(t, a), methodSpec(t, b)));
}
object
hashMapFindNode(Thread* t, object map, object key,
uint32_t (*hash)(Thread*, object),
bool (*equal)(Thread*, object, object));
inline object
hashMapFind(Thread* t, object map, object key,
uint32_t (*hash)(Thread*, object),
bool (*equal)(Thread*, object, object))
{
object n = hashMapFindNode(t, map, key, hash, equal);
return (n ? tripleSecond(t, n) : 0);
}
void
hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object),
unsigned size);
void
hashMapInsert(Thread* t, object map, object key, object value,
uint32_t (*hash)(Thread*, object));
inline bool
hashMapInsertOrReplace(Thread* t, object map, object key, object value,
uint32_t (*hash)(Thread*, object),
bool (*equal)(Thread*, object, object))
{
object n = hashMapFindNode(t, map, key, hash, equal);
if (n == 0) {
hashMapInsert(t, map, key, value, hash);
return true;
} else {
set(t, tripleSecond(t, n), value);
return false;
}
}
object
hashMapRemove(Thread* t, object map, object key,
uint32_t (*hash)(Thread*, object),
bool (*equal)(Thread*, object, object));
} // namespace vm
#endif//JNI_VM_H
#endif//VM_DECLARATIONS_H

66
src/vm-jni.cpp Normal file
View File

@ -0,0 +1,66 @@
#include "vm-jni.h"
#include "vm-declarations.h"
namespace vm {
namespace jni {
jsize
GetStringUTFLength(JNIEnv* e, jstring s)
{
Thread* t = static_cast<Thread*>(e);
ENTER(t, Thread::ActiveState);
jsize length = 0;
if (LIKELY(s)) {
length = stringLength(t, *s);
} else {
t->exception = makeNullPointerException(t);
}
return length;
}
const char*
GetStringUTFChars(JNIEnv* e, jstring s, jboolean* isCopy)
{
Thread* t = static_cast<Thread*>(e);
ENTER(t, Thread::ActiveState);
char* chars = 0;
if (LIKELY(s)) {
chars = static_cast<char*>
(t->vm->system->allocate(stringLength(t, *s) + 1));
memcpy(chars,
&byteArrayBody(t, stringBytes(t, *s), stringOffset(t, *s)),
stringLength(t, *s));
chars[stringLength(t, *s)] = 0;
} else {
t->exception = makeNullPointerException(t);
}
if (isCopy) *isCopy = true;
return chars;
}
void
ReleaseStringUTFChars(JNIEnv* e, jstring, const char* chars)
{
static_cast<Thread*>(e)->vm->system->free(chars);
}
void
populate(JNIEnvVTable* table)
{
memset(table, 0, sizeof(JNIEnvVTable));
table->GetStringUTFLength = jni::GetStringUTFLength;
table->GetStringUTFChars = jni::GetStringUTFChars;
table->ReleaseStringUTFChars = jni::ReleaseStringUTFChars;
}
} // namespace jni
} // namespace vm

15
src/vm-jni.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef VM_JNI_H
#define VM_JNI_H
#include "vm-declarations.h"
namespace vm {
namespace jni {
void
populate(JNIEnvVTable* table);
} // namespace jni
} // namespace vm
#endif//VM_JNI_H

1647
src/vm.cpp

File diff suppressed because it is too large Load Diff