corda/src/vm.cpp

2851 lines
66 KiB
C++
Raw Normal View History

#include "common.h"
#include "system.h"
#include "heap.h"
2007-06-14 23:55:06 +00:00
#include "class_finder.h"
2007-06-16 01:02:24 +00:00
#include "stream.h"
#include "constants.h"
#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)
2007-06-14 23:55:06 +00:00
using namespace vm;
2007-05-21 15:47:44 +00:00
namespace {
typedef void* object;
2007-06-05 00:28:52 +00:00
typedef unsigned Type;
class Thread;
void assert(Thread*, bool);
object resolveClass(Thread*, object);
object allocate(Thread* t, unsigned size);
inline unsigned
pad(unsigned n)
{
unsigned extra = n % sizeof(void*);
return (extra ? n + sizeof(void*) - extra : n);
}
2007-06-05 00:28:52 +00:00
2007-06-17 22:03:27 +00:00
template <class T>
inline T&
cast(object p, unsigned offset)
{
return *reinterpret_cast<T*>(static_cast<uint8_t*>(p) + offset);
}
object&
objectClass(object o)
{
return cast<object>(o, 0);
}
class Machine {
public:
System* sys;
Heap* heap;
2007-06-14 23:55:06 +00:00
ClassFinder* classFinder;
Thread* rootThread;
Thread* exclusive;
unsigned activeCount;
unsigned liveCount;
System::Monitor* stateLock;
System::Monitor* heapLock;
2007-06-14 23:55:06 +00:00
System::Monitor* classLock;
object classMap;
#include "type-members.cpp"
};
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 HeapSize = 64 * 1024;
static const unsigned StackSize = 64 * 1024;
Machine* vm;
Thread* next;
Thread* child;
State state;
object thread;
object frame;
object code;
object exception;
unsigned ip;
unsigned sp;
unsigned heapIndex;
object stack[StackSize];
object heap[HeapSize];
Protector* protector;
};
#include "type-declarations.cpp"
#include "type-constructors.cpp"
void enter(Thread* t, Thread::State state);
2007-06-14 23:55:06 +00:00
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);
enter(t, Thread::ActiveState);
}
}
~MonitorResource() { m->release(t); }
2007-06-14 23:55:06 +00:00
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;
2007-06-14 23:55:06 +00:00
System::Monitor* m;
};
inline void NO_RETURN
abort(Thread* t)
{
2007-06-18 04:25:42 +00:00
t->vm->sys->abort(); // this should not return
::abort();
}
inline void
assert(Thread* t, bool v)
{
if (UNLIKELY(not v)) abort(t);
}
void
2007-06-14 23:55:06 +00:00
init(Machine* m, System* sys, Heap* heap, ClassFinder* classFinder)
{
memset(m, 0, sizeof(Machine));
m->sys = sys;
m->heap = heap;
2007-06-14 23:55:06 +00:00
m->classFinder = classFinder;
if (not sys->success(sys->make(&(m->stateLock))) or
2007-06-14 23:55:06 +00:00
not sys->success(sys->make(&(m->heapLock))) or
not sys->success(sys->make(&(m->classLock))))
{
sys->abort();
}
}
void
dispose(Machine* m)
{
m->stateLock->dispose();
m->heapLock->dispose();
m->classLock->dispose();
}
void
init(Thread* t, Machine* m)
{
memset(t, 0, sizeof(Thread));
t->vm = m;
m->rootThread = t;
t->state = Thread::NoState;
#include "type-initializations.cpp"
}
2007-06-02 00:06:06 +00:00
void
iterate(Thread* t, Heap::Visitor* v)
{
t->heapIndex = 0;
v->visit(&(t->thread));
2007-06-02 00:06:06 +00:00
v->visit(&(t->frame));
v->visit(&(t->code));
v->visit(&(t->exception));
for (unsigned i = 0; i < t->sp; ++i) {
v->visit(t->stack + t->sp);
}
for (Thread::Protector* p = t->protector; p; p = p->next) {
v->visit(p->p);
}
2007-06-02 00:06:06 +00:00
for (Thread* t = t->child; t; t = t->next) {
iterate(t, v);
}
}
void
collect(Machine* m, Heap::CollectionType type)
{
2007-06-05 00:28:52 +00:00
class Iterator: public Heap::Iterator {
2007-06-02 00:06:06 +00:00
public:
2007-06-14 23:55:06 +00:00
Iterator(Machine* m): m(m) { }
2007-06-02 00:06:06 +00:00
void iterate(Heap::Visitor* v) {
2007-06-14 23:55:06 +00:00
v->visit(&(m->classMap));
for (Thread* t = m->rootThread; t; t = t->next) {
2007-06-02 00:06:06 +00:00
::iterate(t, v);
}
}
private:
2007-06-14 23:55:06 +00:00
Machine* m;
2007-06-02 00:06:06 +00:00
} it(m);
m->heap->collect(type, &it);
2007-06-02 00:06:06 +00:00
}
void
enter(Thread* t, Thread::State s)
2007-06-02 00:06:06 +00:00
{
2007-06-05 00:28:52 +00:00
if (s == t->state) return;
2007-06-02 00:06:06 +00:00
ACQUIRE_RAW(t, t->vm->stateLock);
2007-06-02 00:06:06 +00:00
switch (s) {
2007-06-05 00:28:52 +00:00
case Thread::ExclusiveState: {
assert(t, t->state == Thread::ActiveState);
2007-06-02 00:06:06 +00:00
while (t->vm->exclusive) {
// another thread got here first.
enter(t, Thread::IdleState);
enter(t, Thread::ActiveState);
2007-06-02 00:06:06 +00:00
}
2007-06-05 00:28:52 +00:00
t->state = Thread::ExclusiveState;
2007-06-02 00:06:06 +00:00
t->vm->exclusive = t;
2007-06-02 00:06:06 +00:00
while (t->vm->activeCount > 1) {
t->vm->stateLock->wait(t);
2007-06-02 00:06:06 +00:00
}
} break;
2007-06-02 00:06:06 +00:00
2007-06-05 00:28:52 +00:00
case Thread::IdleState:
case Thread::ZombieState: {
switch (t->state) {
case Thread::ExclusiveState: {
assert(t, t->vm->exclusive == t);
t->vm->exclusive = 0;
} break;
2007-06-05 00:28:52 +00:00
case Thread::ActiveState: break;
default: abort(t);
}
-- t->vm->activeCount;
2007-06-05 00:28:52 +00:00
if (s == Thread::ZombieState) {
-- t->vm->liveCount;
}
t->state = s;
2007-06-02 00:06:06 +00:00
t->vm->stateLock->notifyAll(t);
} break;
2007-06-05 00:28:52 +00:00
case Thread::ActiveState: {
switch (t->state) {
case Thread::ExclusiveState: {
assert(t, t->vm->exclusive == t);
t->state = s;
t->vm->exclusive = 0;
t->vm->stateLock->notifyAll(t);
} break;
2007-06-05 00:28:52 +00:00
case Thread::NoState:
case Thread::IdleState: {
while (t->vm->exclusive) {
t->vm->stateLock->wait(t);
}
++ t->vm->activeCount;
2007-06-05 00:28:52 +00:00
if (t->state == Thread::NoState) {
++ t->vm->liveCount;
}
t->state = s;
} break;
default: abort(t);
}
} break;
2007-06-05 00:28:52 +00:00
case Thread::ExitState: {
switch (t->state) {
case Thread::ExclusiveState: {
assert(t, t->vm->exclusive == t);
t->vm->exclusive = 0;
} break;
2007-06-05 00:28:52 +00:00
case Thread::ActiveState: break;
default: abort(t);
}
-- t->vm->activeCount;
t->state = s;
while (t->vm->liveCount > 1) {
t->vm->stateLock->wait(t);
}
} break;
default: abort(t);
2007-06-02 00:06:06 +00:00
}
}
2007-06-02 00:06:06 +00:00
void
maybeYieldAndMaybeCollect(Thread* t, unsigned size)
{
if (size > Thread::HeapSize) {
// large object support not yet implemented.
abort(t);
}
ACQUIRE_RAW(t, t->vm->stateLock);
while (t->vm->exclusive) {
// another thread wants to enter the exclusive state, either for a
// collection or some other reason. We give it a chance here.
enter(t, Thread::IdleState);
enter(t, Thread::ActiveState);
}
if (t->heapIndex + size >= Thread::HeapSize) {
enter(t, Thread::ExclusiveState);
collect(t->vm, Heap::MinorCollection);
enter(t, Thread::ActiveState);
}
2007-06-02 00:06:06 +00:00
}
inline object
allocate(Thread* t, unsigned size)
{
if (UNLIKELY(t->heapIndex + size >= Thread::HeapSize
2007-06-02 00:06:06 +00:00
or t->vm->exclusive))
{
maybeYieldAndMaybeCollect(t, size);
2007-06-02 00:06:06 +00:00
}
object o = t->heap + t->heapIndex;
t->heapIndex += size;
return o;
2007-06-02 00:06:06 +00:00
}
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);
}
}
inline void
push(Thread* t, object o)
{
t->stack[(t->sp)++] = o;
}
inline object
pop(Thread* t)
{
return t->stack[--(t->sp)];
}
inline object&
top(Thread* t)
{
return t->stack[t->sp - 1];
}
inline object
make(Thread* t, object class_)
{
PROTECT(t, class_);
unsigned size = classFixedSize(t, class_);
object instance = allocate(t, size);
*static_cast<object*>(instance) = class_;
memset(static_cast<object*>(instance) + sizeof(object), 0,
size - sizeof(object));
return instance;
}
object
makeString(Thread* t, const char* format, ...)
{
static const unsigned Size = 256;
char buffer[Size];
va_list a;
va_start(a, format);
vsnprintf(buffer, Size - 1, format, a);
va_end(a);
object s = makeByteArray(t, strlen(buffer) + 1);
memcpy(byteArrayBody(t, s), buffer, byteArrayLength(t, s));
return makeString(t, s, 0, byteArrayLength(t, s), 0);
}
object
makeTrace(Thread* t)
{
object trace = 0;
PROTECT(t, trace);
frameIp(t, t->frame) = t->ip;
for (; t->frame; t->frame = frameNext(t, t->frame)) {
trace = makeTrace
(t, frameMethod(t, t->frame), frameIp(t, t->frame), trace);
}
return trace;
}
object
makeArrayIndexOutOfBoundsException(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeArrayIndexOutOfBoundsException(t, message, trace);
}
object
makeNegativeArrayStoreException(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeNegativeArrayStoreException(t, message, trace);
}
object
makeClassCastException(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
2007-06-14 23:55:06 +00:00
return makeClassCastException(t, message, trace);
}
object
makeClassNotFoundException(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeClassNotFoundException(t, message, trace);
}
object
makeNullPointerException(Thread* t)
{
return makeNullPointerException(t, 0, makeTrace(t));
}
object
makeStackOverflowError(Thread* t)
{
return makeStackOverflowError(t, 0, makeTrace(t));
}
object
makeNoSuchFieldError(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeNoSuchFieldError(t, message, trace);
}
object
makeNoSuchMethodError(Thread* t, object message)
{
PROTECT(t, message);
object trace = makeTrace(t);
return makeNoSuchMethodError(t, message, trace);
}
inline bool
2007-06-17 22:03:27 +00:00
isLongOrDouble(Thread* t, object o)
{
2007-06-17 22:03:27 +00:00
return objectClass(o) == t->vm->longClass
or objectClass(o) == t->vm->doubleClass;
}
inline object
getField(Thread* t, object instance, object field)
{
switch (byteArrayBody(t, fieldSpec(t, field))[0]) {
2007-06-16 21:39:05 +00:00
case 'B':
return makeByte(t, cast<int8_t>(instance, fieldOffset(t, field)));
case 'C':
return makeChar(t, cast<int16_t>(instance, fieldOffset(t, field)));
case 'D':
return makeDouble(t, cast<int64_t>(instance, fieldOffset(t, field)));
case 'F':
return makeFloat(t, cast<int32_t>(instance, fieldOffset(t, field)));
case 'I':
return makeInt(t, cast<int32_t>(instance, fieldOffset(t, field)));
case 'J':
return makeLong(t, cast<int64_t>(instance, fieldOffset(t, field)));
case 'S':
return makeShort(t, cast<int16_t>(instance, fieldOffset(t, field)));
case 'Z':
return makeBoolean(t, cast<int8_t>(instance, fieldOffset(t, field)));
case 'L':
case '[':
return cast<object>(instance, fieldOffset(t, field));
default: abort(t);
}
}
inline void
setField(Thread* t, object o, object field, object value)
{
switch (byteArrayBody(t, fieldSpec(t, field))[0]) {
2007-06-16 21:39:05 +00:00
case 'B':
cast<int8_t>(o, fieldOffset(t, field)) = byteValue(t, value);
break;
case 'C':
cast<int16_t>(o, fieldOffset(t, field)) = charValue(t, value);
break;
case 'D':
cast<int64_t>(o, fieldOffset(t, field)) = doubleValue(t, value);
break;
case 'F':
cast<int32_t>(o, fieldOffset(t, field)) = floatValue(t, value);
break;
case 'I':
cast<int32_t>(o, fieldOffset(t, field)) = intValue(t, value);
break;
case 'J':
cast<int64_t>(o, fieldOffset(t, field)) = longValue(t, value);
break;
case 'S':
cast<int16_t>(o, fieldOffset(t, field)) = shortValue(t, value);
break;
case 'Z':
cast<int8_t>(o, fieldOffset(t, field)) = booleanValue(t, value);
break;
case 'L':
case '[':
set(t, cast<object>(o, fieldOffset(t, field)), value);
default: abort(t);
}
}
inline object
getStatic(Thread* t, object field)
{
2007-06-17 22:03:27 +00:00
return arrayBody(t, classStaticTable(t, fieldClass(t, field)))
[fieldOffset(t, field)];
}
inline void
setStatic(Thread* t, object field, object value)
{
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, classStaticTable(t, fieldClass(t, field)))
[fieldOffset(t, field)], value);
}
bool
instanceOf(Thread* t, object class_, object o)
{
if (o == 0) {
return false;
}
2007-06-17 22:03:27 +00:00
if (objectClass(class_) == t->vm->interfaceClass) {
for (object oc = objectClass(o); oc; oc = classSuper(t, oc)) {
object itable = classInterfaceTable(t, oc);
2007-06-17 22:03:27 +00:00
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
if (arrayBody(t, itable)[i] == class_) {
return true;
}
}
}
} else {
for (object oc = objectClass(o); oc; oc = classSuper(t, oc)) {
2007-06-17 22:03:27 +00:00
if (oc == class_) {
return true;
}
}
}
return false;
}
object
findInterfaceMethod(Thread* t, object method, object o)
{
2007-06-17 22:03:27 +00:00
object interface = methodClass(t, method);
object itable = classInterfaceTable(t, objectClass(o));
2007-06-17 22:03:27 +00:00
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
if (arrayBody(t, itable)[i] == interface) {
return arrayBody(t, arrayBody(t, itable)[i + 1])
[methodOffset(t, method)];
}
}
abort(t);
}
inline object
findMethod(Thread* t, object method, object class_)
{
2007-06-17 22:03:27 +00:00
return arrayBody(t, classVirtualTable(t, class_))
[methodOffset(t, method)];
}
inline object
findVirtualMethod(Thread* t, object method, object o)
{
return findMethod(t, method, objectClass(o));
}
bool
isSuperclass(Thread* t, object class_, object base)
{
for (object oc = classSuper(t, base); oc; oc = classSuper(t, oc)) {
2007-06-17 22:03:27 +00:00
if (oc == class_) {
return true;
}
}
return false;
}
inline int
strcmp(const int8_t* a, const int8_t* b)
{
return ::strcmp(reinterpret_cast<const char*>(a),
reinterpret_cast<const char*>(b));
}
inline bool
isSpecialMethod(Thread* t, object method, object class_)
{
return (classFlags(t, class_) & ACC_SUPER)
and strcmp(reinterpret_cast<const int8_t*>("<init>"),
byteArrayBody(t, methodName(t, method))) != 0
and isSuperclass(t, methodClass(t, method), class_);
}
object
2007-06-14 23:55:06 +00:00
find(Thread* t, object class_, object table, object reference,
object& (*name)(Thread*, object),
object& (*spec)(Thread*, object),
object (*makeError)(Thread*, object))
{
object n = referenceName(t, reference);
object s = referenceSpec(t, reference);
2007-06-17 22:03:27 +00:00
for (unsigned i = 0; i < arrayLength(t, table); ++i) {
object field = arrayBody(t, table)[i];
if (strcmp(byteArrayBody(t, name(t, field)),
byteArrayBody(t, n)) == 0 and
strcmp(byteArrayBody(t, spec(t, field)),
byteArrayBody(t, s)) == 0)
{
return field;
}
}
object message = makeString
(t, "%s (%s) not found in %s",
byteArrayBody(t, n),
byteArrayBody(t, s),
byteArrayBody(t, className(t, class_)));
t->exception = makeError(t, message);
return 0;
}
inline object
findFieldInClass(Thread* t, object class_, object reference)
{
2007-06-14 23:55:06 +00:00
return find(t, class_, classFieldTable(t, class_), reference, fieldName,
fieldSpec, makeNoSuchFieldError);
}
inline object
findMethodInClass(Thread* t, object class_, object reference)
{
2007-06-14 23:55:06 +00:00
return find(t, class_, classMethodTable(t, class_), reference, methodName,
methodSpec, makeNoSuchMethodError);
}
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;
}
2007-06-16 21:39:05 +00:00
inline uint32_t
2007-06-17 22:03:27 +00:00
byteArrayHash(Thread* t, object array)
2007-06-16 21:39:05 +00:00
{
return hash(byteArrayBody(t, array), byteArrayLength(t, array) - 1);
}
bool
byteArrayEqual(Thread* t, object a, object b)
{
return a == b or
((byteArrayLength(t, a) == byteArrayLength(t, b)) and
strcmp(byteArrayBody(t, a), byteArrayBody(t, b)) == 0);
}
2007-06-17 22:03:27 +00:00
inline uint32_t
methodHash(Thread* t, object method)
{
return byteArrayHash(t, methodName(t, method))
^ byteArrayHash(t, methodSpec(t, method));
}
2007-06-14 23:55:06 +00:00
bool
methodEqual(Thread* t, object a, object b)
2007-06-14 23:55:06 +00:00
{
2007-06-14 23:56:40 +00:00
return a == b or
(byteArrayEqual(t, methodName(t, a), methodName(t, b)) and
byteArrayEqual(t, methodSpec(t, a), methodSpec(t, b)));
2007-06-14 23:55:06 +00:00
}
object
2007-06-17 22:03:27 +00:00
hashMapFindNode(Thread* t, object map, object key,
uint32_t (*hash)(Thread*, object),
bool (*equal)(Thread*, object, object))
2007-06-14 23:55:06 +00:00
{
2007-06-17 22:03:27 +00:00
object array = hashMapArray(t, map);
if (array) {
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
object n = arrayBody(t, array)[index];
while (n) {
if (equal(t, tripleFirst(t, n), key)) {
return n;
}
n = tripleThird(t, n);
2007-06-14 23:55:06 +00:00
}
}
return 0;
}
2007-06-17 22:03:27 +00:00
inline object
hashMapFind(Thread* t, object map, object key,
uint32_t (*hash)(Thread*, object),
bool (*equal)(Thread*, object, object))
2007-06-14 23:55:06 +00:00
{
2007-06-17 22:03:27 +00:00
object n = hashMapFindNode(t, map, key, hash, equal);
return (n ? tripleSecond(t, n) : 0);
}
2007-06-14 23:55:06 +00:00
2007-06-17 22:03:27 +00:00
void
hashMapGrow(Thread* t, object map, uint32_t (*hash)(Thread*, object))
{
2007-06-14 23:55:06 +00:00
PROTECT(t, map);
2007-06-17 22:03:27 +00:00
object oldArray = hashMapArray(t, map);
unsigned oldLength = (oldArray ? arrayLength(t, oldArray) : 0);
PROTECT(t, oldArray);
unsigned newLength = (oldLength ? oldLength * 2 : 32);
object newArray = makeArray(t, newLength);
memset(arrayBody(t, newArray), 0, newLength * sizeof(object));
2007-06-17 22:03:27 +00:00
if (oldArray) {
for (unsigned i = 0; i < oldLength; ++i) {
2007-06-17 22:03:27 +00:00
object next;
for (object p = arrayBody(t, oldArray)[i]; p; p = next) {
next = tripleThird(t, p);
object key = tripleFirst(t, p);
unsigned index = hash(t, key) & (newLength - 1);
object n = arrayBody(t, newArray)[index];
set(t, tripleThird(t, p), n);
set(t, arrayBody(t, newArray)[index], p);
}
}
}
set(t, hashMapArray(t, map), newArray);
}
void
hashMapInsert(Thread* t, object map, object key, object value,
uint32_t (*hash)(Thread*, object))
{
object array = hashMapArray(t, map);
PROTECT(t, array);
++ hashMapSize(t, map);
if (array == 0 or hashMapSize(t, map) >= arrayLength(t, array) * 2) {
PROTECT(t, map);
PROTECT(t, key);
PROTECT(t, value);
2007-06-17 22:03:27 +00:00
hashMapGrow(t, map, hash);
array = hashMapArray(t, map);
}
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
2007-06-17 22:03:27 +00:00
object n = arrayBody(t, array)[index];
2007-06-14 23:55:06 +00:00
n = makeTriple(t, key, value, n);
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, array)[index], n);
}
object
hashMapIterator(Thread* t, object map)
{
object array = hashMapArray(t, map);
if (array) {
for (unsigned i = 0; i < arrayLength(t, array); ++i) {
if (arrayBody(t, array)[i]) {
return makeHashMapIterator(t, map, arrayBody(t, array)[i], i + 1);
}
}
}
return 0;
}
object
hashMapIteratorNext(Thread* t, object it)
{
object map = hashMapIteratorMap(t, it);
object node = hashMapIteratorNode(t, it);
unsigned index = hashMapIteratorIndex(t, it);
if (tripleThird(t, node)) {
return makeHashMapIterator(t, map, tripleThird(t, node), index + 1);
} else {
object array = hashMapArray(t, map);
for (unsigned i = index; i < arrayLength(t, array); ++i) {
if (arrayBody(t, array)[i]) {
return makeHashMapIterator(t, map, arrayBody(t, array)[i], i + 1);
}
}
return 0;
}
}
2007-06-17 22:03:27 +00:00
void
listAppend(Thread* t, object list, object value)
{
PROTECT(t, list);
++ listSize(t, list);
object p = makePair(t, value, 0);
if (listFront(t, list)) {
set(t, pairSecond(t, listRear(t, list)), p);
} else {
set(t, listFront(t, list), p);
}
set(t, listRear(t, list), p);
2007-06-14 23:55:06 +00:00
}
2007-06-16 21:39:05 +00:00
void
parseInterfaceTable(Thread* t, Stream& s, object class_, object pool)
{
PROTECT(t, class_);
PROTECT(t, pool);
object map = makeHashMap(t, 0, 0);
PROTECT(t, map);
object superInterfaces = classInterfaceTable(t, classSuper(t, class_));
PROTECT(t, superInterfaces);
2007-06-17 22:03:27 +00:00
for (unsigned i = 0; i < arrayLength(t, superInterfaces); i += 2) {
object name = interfaceName(t, arrayBody(t, superInterfaces)[i]);
hashMapInsert(t, map, name, name, byteArrayHash);
2007-06-16 21:39:05 +00:00
}
unsigned count = s.read2();
for (unsigned i = 0; i < count; ++i) {
2007-06-17 22:03:27 +00:00
object name = arrayBody(t, pool)[s.read2()];
hashMapInsert(t, map, name, name, byteArrayHash);
2007-06-16 21:39:05 +00:00
}
object interfaceTable = 0;
if (hashMapSize(t, map)) {
2007-06-17 22:03:27 +00:00
interfaceTable = makeArray(t, hashMapSize(t, map));
2007-06-17 23:25:58 +00:00
PROTECT(t, interfaceTable);
2007-06-16 21:39:05 +00:00
unsigned i = 0;
object it = hashMapIterator(t, map);
2007-06-17 23:25:58 +00:00
PROTECT(t, it);
for (; it; it = hashMapIteratorNext(t, it)) {
object interface = resolveClass
(t, tripleFirst(t, hashMapIteratorNode(t, it)));
2007-06-17 23:25:58 +00:00
if (UNLIKELY(t->exception)) return;
set(t, arrayBody(t, interfaceTable)[i++], interface);
// we'll fill in this table in parseMethodTable():
object vtable = makeArray
(t, arrayLength(t, interfaceMethodTable(t, interface)));
2007-06-17 23:25:58 +00:00
set(t, arrayBody(t, interfaceTable)[i++], vtable);
2007-06-16 21:39:05 +00:00
}
}
set(t, classInterfaceTable(t, class_), interfaceTable);
}
bool
isReferenceField(Thread* t, object field)
{
switch (byteArrayBody(t, fieldSpec(t, field))[0]) {
case 'L':
case '[':
return true;
default:
return false;
}
}
unsigned
fieldSize(Thread* t, object field)
{
switch (byteArrayBody(t, fieldSpec(t, field))[0]) {
case 'B':
return 1;
case 'C':
case 'S':
case 'Z':
return 2;
case 'D':
case 'J':
return 8;
case 'F':
case 'I':
return 4;
case 'L':
case '[':
return sizeof(void*);
default: abort(t);
}
}
2007-06-16 21:39:05 +00:00
void
parseFieldTable(Thread* t, Stream& s, object class_, object pool)
{
PROTECT(t, class_);
PROTECT(t, pool);
unsigned count = s.read2();
if (count) {
unsigned memberOffset
= classFixedSize(t, classSuper(t, class_)) * sizeof(void*);
unsigned staticOffset = 0;
2007-06-17 22:03:27 +00:00
object fieldTable = makeArray(t, count);
2007-06-16 21:39:05 +00:00
PROTECT(t, fieldTable);
for (unsigned i = 0; i < count; ++i) {
unsigned flags = s.read2();
unsigned name = s.read2();
unsigned spec = s.read2();
unsigned attributeCount = s.read2();
for (unsigned j = 0; j < attributeCount; ++j) {
s.read2();
s.skip(s.read4());
}
object value = makeField(t,
flags,
0, // offset
2007-06-17 22:03:27 +00:00
arrayBody(t, pool)[name],
arrayBody(t, pool)[spec],
2007-06-16 21:39:05 +00:00
class_);
if (flags & ACC_STATIC) {
fieldOffset(t, value) = staticOffset++;
} else {
unsigned excess = memberOffset % sizeof(void*);
if (excess and isReferenceField(t, value)) {
memberOffset += sizeof(void*) - excess;
2007-06-16 21:39:05 +00:00
}
fieldOffset(t, value) = memberOffset;
memberOffset += fieldSize(t, value);
}
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, fieldTable)[i], value);
2007-06-16 21:39:05 +00:00
}
set(t, classFieldTable(t, class_), fieldTable);
if (staticOffset) {
2007-06-17 22:03:27 +00:00
object staticTable = makeArray(t, staticOffset);
memset(arrayBody(t, staticTable), 0, staticOffset * sizeof(void*));
2007-06-16 21:39:05 +00:00
set(t, classStaticTable(t, class_), staticTable);
}
}
}
object
2007-06-17 23:25:58 +00:00
parseCode(Thread* t, Stream& s, object pool)
2007-06-16 21:39:05 +00:00
{
2007-06-17 23:25:58 +00:00
unsigned maxStack = s.read2();
unsigned maxLocals = s.read2();
unsigned length = s.read4();
object code = makeCode(t, pool, 0, maxStack, maxLocals, length);
s.read(codeBody(t, code), length);
unsigned ehtLength = s.read2();
if (ehtLength) {
PROTECT(t, code);
object eht = makeExceptionHandlerTable(t, ehtLength);
for (unsigned i = 0; i < ehtLength; ++i) {
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
exceptionHandlerStart(eh) = s.read2();
exceptionHandlerEnd(eh) = s.read2();
exceptionHandlerIp(eh) = s.read2();
exceptionHandlerCatchType(eh) = s.read2();
2007-06-17 23:25:58 +00:00
}
set(t, codeExceptionHandlerTable(t, code), eht);
}
unsigned attributeCount = s.read2();
for (unsigned j = 0; j < attributeCount; ++j) {
s.read2();
s.skip(s.read4());
}
2007-06-18 04:25:42 +00:00
return code;
2007-06-16 21:39:05 +00:00
}
unsigned
parameterCount(Thread* t, object spec)
{
unsigned count = 0;
const char* s = reinterpret_cast<const char*>(byteArrayBody(t, spec));
++ s; // skip '('
while (*s and *s != ')') {
switch (*s) {
case 'L':
while (*s and *s != ';') ++ s;
++ s;
break;
case '[':
while (*s == '[') ++ s;
break;
default:
++ s;
break;
}
++ count;
}
return count;
}
2007-06-16 21:39:05 +00:00
void
parseMethodTable(Thread* t, Stream& s, object class_, object pool)
2007-06-16 21:39:05 +00:00
{
PROTECT(t, class_);
PROTECT(t, pool);
object map = makeHashMap(t, 0, 0);
PROTECT(t, map);
unsigned virtualCount = 0;
object superVirtualTable = classVirtualTable(t, classSuper(t, class_));
2007-06-17 22:03:27 +00:00
PROTECT(t, superVirtualTable);
2007-06-16 21:39:05 +00:00
2007-06-17 22:03:27 +00:00
if (superVirtualTable) {
virtualCount = arrayLength(t, superVirtualTable);
2007-06-16 21:39:05 +00:00
for (unsigned i = 0; i < virtualCount; ++i) {
2007-06-17 22:03:27 +00:00
object method = arrayBody(t, superVirtualTable)[i];
hashMapInsert(t, map, method, method, byteArrayHash);
2007-06-16 21:39:05 +00:00
}
}
object newVirtuals = makeList(t, 0, 0, 0);
PROTECT(t, newVirtuals);
unsigned count = s.read2();
if (count) {
2007-06-17 22:03:27 +00:00
object methodTable = makeArray(t, count);
2007-06-16 21:39:05 +00:00
PROTECT(t, methodTable);
for (unsigned i = 0; i < count; ++i) {
unsigned flags = s.read2();
unsigned name = s.read2();
unsigned spec = s.read2();
object code = 0;
unsigned attributeCount = s.read2();
for (unsigned j = 0; j < attributeCount; ++j) {
2007-06-17 22:03:27 +00:00
object name = arrayBody(t, pool)[s.read2()];
2007-06-17 23:25:58 +00:00
unsigned length = s.read4();
2007-06-16 21:39:05 +00:00
if (strcmp(reinterpret_cast<const int8_t*>("Code"),
byteArrayBody(t, name)) == 0)
{
2007-06-17 23:25:58 +00:00
code = parseCode(t, s, pool);
2007-06-16 21:39:05 +00:00
} else {
2007-06-17 23:25:58 +00:00
s.skip(length);
2007-06-16 21:39:05 +00:00
}
}
object value = makeMethod(t,
flags,
0, // offset
parameterCount(t, arrayBody(t, pool)[spec]),
2007-06-17 22:03:27 +00:00
arrayBody(t, pool)[name],
arrayBody(t, pool)[spec],
2007-06-16 21:39:05 +00:00
class_,
code);
2007-06-17 23:25:58 +00:00
PROTECT(t, value);
2007-06-16 21:39:05 +00:00
2007-06-17 23:25:58 +00:00
if (flags & ACC_STATIC) {
if (strcmp(reinterpret_cast<const int8_t*>("<clinit>"),
byteArrayBody(t, methodName(t, value))) == 0)
{
set(t, classInitializer(t, class_), value);
}
} else {
object p = hashMapFindNode(t, map, value, methodHash, methodEqual);
2007-06-16 21:39:05 +00:00
if (p) {
methodOffset(t, value) = methodOffset(t, tripleFirst(t, p));
set(t, tripleSecond(t, p), value);
} else {
methodOffset(t, value) = virtualCount++;
2007-06-16 21:39:05 +00:00
listAppend(t, newVirtuals, value);
}
}
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, methodTable)[i], value);
2007-06-16 21:39:05 +00:00
}
set(t, classMethodTable(t, class_), methodTable);
}
if (virtualCount) {
2007-06-17 23:25:58 +00:00
// generate class vtable
2007-06-17 22:03:27 +00:00
object vtable = makeArray(t, virtualCount);
2007-06-16 21:39:05 +00:00
2007-06-17 22:03:27 +00:00
if (superVirtualTable) {
2007-06-17 23:25:58 +00:00
unsigned i = 0;
2007-06-17 22:03:27 +00:00
for (; i < arrayLength(t, superVirtualTable); ++i) {
object method = arrayBody(t, superVirtualTable)[i];
method = hashMapFind(t, map, method, methodHash, methodEqual);
2007-06-16 21:39:05 +00:00
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, vtable)[i], method);
2007-06-16 21:39:05 +00:00
}
for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) {
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, vtable)[i++], pairFirst(t, p));
2007-06-16 21:39:05 +00:00
}
}
2007-06-17 22:03:27 +00:00
set(t, classVirtualTable(t, class_), vtable);
2007-06-17 23:25:58 +00:00
// generate interface vtables
object itable = classInterfaceTable(t, class_);
PROTECT(t, itable);
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
object methodTable = interfaceMethodTable(t, arrayBody(t, itable)[i]);
object vtable = arrayBody(t, itable)[i + 1];
for (unsigned j = 0; j < arrayLength(t, methodTable); ++j) {
object method = arrayBody(t, methodTable)[j];
method = hashMapFind(t, map, method, methodHash, methodEqual);
set(t, arrayBody(t, vtable)[j], method);
}
}
2007-06-16 21:39:05 +00:00
}
}
2007-06-16 01:02:24 +00:00
object
parseClass(Thread* t, const uint8_t* data, unsigned size)
{
class Client : public Stream::Client {
public:
Client(Thread* t): t(t) { }
virtual void NO_RETURN handleEOS() {
abort(t);
}
private:
Thread* t;
} client(t);
Stream s(&client, data, size);
uint32_t magic = s.read4();
assert(t, magic == 0xCAFEBABE);
s.read2(); // minor version
s.read2(); // major version
unsigned poolCount = s.read2();
2007-06-17 22:03:27 +00:00
object pool = makeArray(t, poolCount);
2007-06-16 01:02:24 +00:00
PROTECT(t, pool);
for (unsigned i = 0; i < poolCount; ++i) {
switch (s.read1()) {
case CONSTANT_Class: {
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, pool)[i], arrayBody(t, pool)[s.read2()]);
2007-06-16 01:02:24 +00:00
} break;
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref: {
2007-06-17 22:03:27 +00:00
object c = arrayBody(t, pool)[s.read2()];
object nameAndType = arrayBody(t, pool)[s.read2()];
2007-06-16 01:02:24 +00:00
object value = makeReference
(t, c, pairFirst(t, nameAndType), pairSecond(t, nameAndType));
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, pool)[i], value);
2007-06-16 01:02:24 +00:00
} break;
case CONSTANT_String: {
2007-06-17 22:03:27 +00:00
object bytes = arrayBody(t, pool)[s.read2()];
2007-06-16 01:02:24 +00:00
object value = makeString(t, bytes, 0, byteArrayLength(t, bytes), 0);
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, pool)[i], value);
2007-06-16 01:02:24 +00:00
} break;
case CONSTANT_Integer: {
object value = makeInt(t, s.read4());
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, pool)[i], value);
2007-06-16 01:02:24 +00:00
} break;
case CONSTANT_Float: {
object value = makeFloat(t, s.readFloat());
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, pool)[i], value);
2007-06-16 01:02:24 +00:00
} break;
case CONSTANT_Long: {
object value = makeLong(t, s.read8());
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, pool)[i], value);
2007-06-16 01:02:24 +00:00
} break;
case CONSTANT_Double: {
object value = makeLong(t, s.readDouble());
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, pool)[i], value);
2007-06-16 01:02:24 +00:00
} break;
case CONSTANT_NameAndType: {
2007-06-17 22:03:27 +00:00
object name = arrayBody(t, pool)[s.read2()];
object type = arrayBody(t, pool)[s.read2()];
2007-06-16 01:02:24 +00:00
object value = makePair(t, name, type);
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, pool)[i], value);
2007-06-16 01:02:24 +00:00
} break;
case CONSTANT_Utf8: {
unsigned length = s.read2();
object value = makeByteArray(t, length + 1);
2007-06-16 01:02:24 +00:00
s.read(reinterpret_cast<uint8_t*>(byteArrayBody(t, value)), length);
byteArrayBody(t, value)[length] = 0;
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, pool)[i], value);
2007-06-16 01:02:24 +00:00
} break;
default: abort(t);
}
}
unsigned flags = s.read2();
unsigned name = s.read2();
object class_ = makeClass(t,
flags,
2007-06-16 01:02:24 +00:00
0, // fixed size
0, // array size
0, // object mask
2007-06-17 22:03:27 +00:00
arrayBody(t, pool)[name],
2007-06-16 21:39:05 +00:00
0, // super
0, // interfaces
0, // vtable
2007-06-16 01:02:24 +00:00
0, // fields
0, // methods
0, // static table
0); // initializer
2007-06-16 01:02:24 +00:00
PROTECT(t, class_);
2007-06-16 21:39:05 +00:00
2007-06-17 22:03:27 +00:00
object super = resolveClass(t, arrayBody(t, pool)[s.read2()]);
2007-06-16 21:39:05 +00:00
if (UNLIKELY(t->exception)) return 0;
2007-06-16 01:02:24 +00:00
2007-06-16 21:39:05 +00:00
set(t, classSuper(t, class_), super);
parseInterfaceTable(t, s, class_, pool);
2007-06-17 23:25:58 +00:00
if (UNLIKELY(t->exception)) return 0;
2007-06-16 01:02:24 +00:00
2007-06-16 21:39:05 +00:00
parseFieldTable(t, s, class_, pool);
2007-06-17 23:25:58 +00:00
if (UNLIKELY(t->exception)) return 0;
2007-06-16 01:02:24 +00:00
2007-06-16 21:39:05 +00:00
parseMethodTable(t, s, class_, pool);
2007-06-17 23:25:58 +00:00
if (UNLIKELY(t->exception)) return 0;
2007-06-16 01:02:24 +00:00
return class_;
}
2007-06-14 23:55:06 +00:00
object
resolveClass(Thread* t, object spec)
{
PROTECT(t, spec);
ACQUIRE(t, t->vm->classLock);
2007-06-17 22:03:27 +00:00
object class_ = hashMapFind
(t, t->vm->classMap, spec, byteArrayHash, byteArrayEqual);
2007-06-14 23:55:06 +00:00
if (class_ == 0) {
unsigned size;
const uint8_t* data = t->vm->classFinder->find
(reinterpret_cast<const char*>(byteArrayBody(t, spec)), &size);
if (data) {
2007-06-16 01:02:24 +00:00
// parse class file
2007-06-14 23:55:06 +00:00
class_ = parseClass(t, data, size);
t->vm->classFinder->free(data);
2007-06-14 23:55:06 +00:00
PROTECT(t, class_);
2007-06-16 01:02:24 +00:00
2007-06-17 22:03:27 +00:00
hashMapInsert(t, t->vm->classMap, spec, class_, byteArrayHash);
2007-06-14 23:55:06 +00:00
} else {
object message = makeString(t, "%s", byteArrayBody(t, spec));
t->exception = makeClassNotFoundException(t, message);
}
}
return class_;
}
inline object
resolveClass(Thread* t, object pool, unsigned index)
{
2007-06-17 22:03:27 +00:00
object o = arrayBody(t, pool)[index];
if (objectClass(o) == t->vm->byteArrayClass) {
2007-06-14 23:55:06 +00:00
PROTECT(t, pool);
o = resolveClass(t, o);
if (UNLIKELY(t->exception)) return 0;
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, pool)[index], o);
2007-06-14 23:55:06 +00:00
}
return o;
}
inline object
resolveClass(Thread* t, object container, object& (*class_)(Thread*, object))
{
object o = class_(t, container);
2007-06-17 22:03:27 +00:00
if (objectClass(o) == t->vm->byteArrayClass) {
2007-06-14 23:55:06 +00:00
PROTECT(t, container);
o = resolveClass(t, o);
if (UNLIKELY(t->exception)) return 0;
set(t, class_(t, container), o);
}
return o;
}
inline object
resolve(Thread* t, object pool, unsigned index,
object (*find)(Thread*, object, object))
{
2007-06-17 22:03:27 +00:00
object o = arrayBody(t, pool)[index];
if (objectClass(o) == t->vm->byteArrayClass) {
PROTECT(t, pool);
2007-06-14 23:55:06 +00:00
object class_ = resolveClass(t, o, referenceClass);
if (UNLIKELY(t->exception)) return 0;
2007-06-17 22:03:27 +00:00
o = find(t, class_, arrayBody(t, pool)[index]);
if (UNLIKELY(t->exception)) return 0;
2007-06-17 22:03:27 +00:00
set(t, arrayBody(t, pool)[index], o);
}
return o;
}
inline object
resolveField(Thread* t, object pool, unsigned index)
{
return resolve(t, pool, index, findFieldInClass);
}
inline object
resolveMethod(Thread* t, object pool, unsigned index)
{
return resolve(t, pool, index, findMethodInClass);
}
2007-05-21 15:47:44 +00:00
object
run(Thread* t)
{
unsigned& ip = t->ip;
unsigned& sp = t->sp;
object& code = t->code;
object& frame = t->frame;
object& exception = t->exception;
object* stack = t->stack;
2007-05-30 00:08:10 +00:00
unsigned parameterCount = 0;
2007-05-21 15:47:44 +00:00
loop:
switch (codeBody(t, code)[ip++]) {
2007-05-21 15:47:44 +00:00
case aaload: {
object index = pop(t);
object array = pop(t);
2007-05-21 15:47:44 +00:00
if (LIKELY(array)) {
2007-06-05 00:28:52 +00:00
int32_t i = intValue(t, index);
if (LIKELY(i >= 0 and
static_cast<uint32_t>(i) < objectArrayLength(t, array)))
{
2007-06-05 00:28:52 +00:00
push(t, objectArrayBody(t, array)[i]);
2007-05-21 15:47:44 +00:00
} else {
object message = makeString(t, "%d not in [0,%d]", i,
objectArrayLength(t, array));
exception = makeArrayIndexOutOfBoundsException(t, message);
2007-05-21 15:47:44 +00:00
goto throw_;
}
} else {
exception = makeNullPointerException(t);
2007-05-21 15:47:44 +00:00
goto throw_;
}
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
case aastore: {
object value = pop(t);
object index = pop(t);
object array = pop(t);
2007-06-05 00:28:52 +00:00
int32_t i = intValue(t, index);
2007-05-21 15:47:44 +00:00
if (LIKELY(array)) {
if (LIKELY(i >= 0 and
static_cast<uint32_t>(i) < objectArrayLength(t, array)))
{
2007-06-06 00:41:04 +00:00
set(t, objectArrayBody(t, array)[i], value);
2007-05-21 15:47:44 +00:00
} else {
object message = makeString(t, "%d not in [0,%d]", i,
objectArrayLength(t, array));
exception = makeArrayIndexOutOfBoundsException(t, message);
2007-05-21 15:47:44 +00:00
goto throw_;
}
} else {
exception = makeNullPointerException(t);
2007-05-21 15:47:44 +00:00
goto throw_;
}
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
case aconst_null: {
push(t, 0);
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
case aload:
case iload:
case lload: {
push(t, frameLocals(t, frame)[codeBody(t, code)[ip++]]);
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
case aload_0:
case iload_0:
case lload_0: {
push(t, frameLocals(t, frame)[0]);
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
case aload_1:
case iload_1:
case lload_1: {
push(t, frameLocals(t, frame)[1]);
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
case aload_2:
case iload_2:
case lload_2: {
push(t, frameLocals(t, frame)[2]);
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
case aload_3:
case iload_3:
case lload_3: {
push(t, frameLocals(t, frame)[3]);
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
case anewarray: {
object count = pop(t);
2007-06-05 00:28:52 +00:00
int32_t c = intValue(t, count);
2007-05-21 15:47:44 +00:00
if (LIKELY(c >= 0)) {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
2007-05-21 15:47:44 +00:00
uint16_t index = (index1 << 8) | index2;
object class_ = resolveClass(t, codePool(t, code), index);
if (UNLIKELY(exception)) goto throw_;
2007-05-21 15:47:44 +00:00
object array = makeObjectArray(t, class_, c);
memset(objectArrayBody(t, array), 0, c * 4);
2007-05-21 15:47:44 +00:00
push(t, array);
2007-05-21 15:47:44 +00:00
} else {
object message = makeString(t, "%d", c);
exception = makeNegativeArrayStoreException(t, message);
2007-05-21 15:47:44 +00:00
goto throw_;
}
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
2007-05-30 00:08:10 +00:00
case areturn:
case ireturn:
case lreturn: {
frame = frameNext(t, frame);
if (frame) {
code = methodCode(t, frameMethod(t, frame));
ip = frameIp(t, frame);
2007-05-21 15:47:44 +00:00
goto loop;
} else {
object value = pop(t);
code = 0;
2007-05-21 15:47:44 +00:00
return value;
}
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
case arraylength: {
object array = pop(t);
if (LIKELY(array)) {
2007-06-17 22:03:27 +00:00
if (objectClass(array) == t->vm->objectArrayClass) {
2007-06-06 00:41:04 +00:00
push(t, makeInt(t, objectArrayLength(t, array)));
} else {
// for all other array types, the length follow the class pointer.
push(t, makeInt(t, cast<uint32_t>(array, sizeof(void*))));
2007-06-06 00:41:04 +00:00
}
2007-05-21 15:47:44 +00:00
} else {
exception = makeNullPointerException(t);
2007-05-21 15:47:44 +00:00
goto throw_;
}
} abort(t);
2007-05-21 15:47:44 +00:00
2007-05-30 00:08:10 +00:00
case astore:
case istore:
case lstore: {
object value = pop(t);
set(t, frameLocals(t, frame)[codeBody(t, code)[ip++]], value);
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
2007-05-30 00:08:10 +00:00
case astore_0:
case istore_0:
case lstore_0: {
object value = pop(t);
set(t, frameLocals(t, frame)[0], value);
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
2007-05-30 00:08:10 +00:00
case astore_1:
case istore_1:
case lstore_1: {
object value = pop(t);
set(t, frameLocals(t, frame)[1], value);
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
2007-05-30 00:08:10 +00:00
case astore_2:
case istore_2:
case lstore_2: {
object value = pop(t);
set(t, frameLocals(t, frame)[2], value);
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
2007-05-30 00:08:10 +00:00
case astore_3:
case istore_3:
case lstore_3: {
object value = pop(t);
set(t, frameLocals(t, frame)[3], value);
2007-05-22 00:05:29 +00:00
} goto loop;
2007-05-21 15:47:44 +00:00
case athrow: {
exception = pop(t);
if (UNLIKELY(exception == 0)) {
exception = makeNullPointerException(t);
2007-05-22 00:05:29 +00:00
}
2007-05-21 15:47:44 +00:00
goto throw_;
} abort(t);
2007-05-22 00:05:29 +00:00
case baload: {
object index = pop(t);
object array = pop(t);
2007-05-22 00:05:29 +00:00
if (LIKELY(array)) {
2007-06-05 00:28:52 +00:00
int32_t i = intValue(t, index);
if (LIKELY(i >= 0 and
static_cast<uint32_t>(i) < byteArrayLength(t, array)))
{
2007-06-06 00:41:04 +00:00
push(t, makeByte(t, byteArrayBody(t, array)[i]));
2007-05-22 00:05:29 +00:00
} else {
object message = makeString(t, "%d not in [0,%d]", i,
byteArrayLength(t, array));
exception = makeArrayIndexOutOfBoundsException(t, message);
2007-05-22 00:05:29 +00:00
goto throw_;
}
} else {
exception = makeNullPointerException(t);
2007-05-22 00:05:29 +00:00
goto throw_;
}
} goto loop;
case bastore: {
object value = pop(t);
object index = pop(t);
object array = pop(t);
2007-06-05 00:28:52 +00:00
int32_t i = intValue(t, index);
2007-05-22 00:05:29 +00:00
if (LIKELY(array)) {
if (LIKELY(i >= 0 and
static_cast<uint32_t>(i) < byteArrayLength(t, array)))
{
2007-06-06 00:41:04 +00:00
byteArrayBody(t, array)[i] = intValue(t, value);
2007-05-22 00:05:29 +00:00
} else {
object message = makeString(t, "%d not in [0,%d]", i,
byteArrayLength(t, array));
exception = makeArrayIndexOutOfBoundsException(t, message);
2007-05-22 00:05:29 +00:00
goto throw_;
}
} else {
exception = makeNullPointerException(t);
2007-05-22 00:05:29 +00:00
goto throw_;
}
} goto loop;
case bipush: {
push(t, makeInt(t, codeBody(t, code)[ip++]));
2007-05-22 00:05:29 +00:00
} goto loop;
case caload: {
object index = pop(t);
object array = pop(t);
2007-05-22 00:05:29 +00:00
if (LIKELY(array)) {
2007-06-05 00:28:52 +00:00
int32_t i = intValue(t, index);
if (LIKELY(i >= 0 and
static_cast<uint32_t>(i) < charArrayLength(t, array)))
{
2007-06-06 00:41:04 +00:00
push(t, makeInt(t, charArrayBody(t, array)[i]));
2007-05-22 00:05:29 +00:00
} else {
object message = makeString(t, "%d not in [0,%d]", i,
charArrayLength(t, array));
exception = makeArrayIndexOutOfBoundsException(t, message);
2007-05-22 00:05:29 +00:00
goto throw_;
}
} else {
exception = makeNullPointerException(t);
2007-05-22 00:05:29 +00:00
goto throw_;
}
} goto loop;
case castore: {
object value = pop(t);
object index = pop(t);
object array = pop(t);
2007-06-05 00:28:52 +00:00
int32_t i = intValue(t, index);
2007-05-22 00:05:29 +00:00
if (LIKELY(array)) {
if (LIKELY(i >= 0 and
static_cast<uint32_t>(i) < charArrayLength(t, array)))
{
2007-06-06 00:41:04 +00:00
charArrayBody(t, array)[i] = intValue(t, value);
2007-05-22 00:05:29 +00:00
} else {
object message = makeString(t, "%d not in [0,%d]", i,
charArrayLength(t, array));
exception = makeArrayIndexOutOfBoundsException(t, message);
2007-05-22 00:05:29 +00:00
goto throw_;
}
} else {
exception = makeNullPointerException(t);
2007-05-22 00:05:29 +00:00
goto throw_;
}
} goto loop;
case checkcast: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
if (stack[sp - 1]) {
2007-05-22 00:05:29 +00:00
uint16_t index = (index1 << 8) | index2;
object class_ = resolveClass(t, codePool(t, code), index);
if (UNLIKELY(exception)) goto throw_;
2007-05-22 00:05:29 +00:00
if (not instanceOf(t, class_, stack[sp - 1])) {
object message = makeString
(t, "%s as %s",
byteArrayBody(t, className(t, objectClass(stack[sp - 1]))),
byteArrayBody(t, className(t, class_)));
exception = makeClassCastException(t, message);
2007-05-22 00:05:29 +00:00
goto throw_;
}
}
} goto loop;
case dup: {
object value = stack[sp - 1];
push(t, value);
2007-05-22 00:05:29 +00:00
} goto loop;
case dup_x1: {
object first = pop(t);
object second = pop(t);
2007-05-22 00:05:29 +00:00
push(t, first);
push(t, second);
push(t, first);
2007-05-22 00:05:29 +00:00
} goto loop;
case dup_x2: {
object first = pop(t);
object second = pop(t);
object third = pop(t);
2007-05-22 00:05:29 +00:00
push(t, first);
push(t, third);
push(t, second);
push(t, first);
2007-05-22 00:05:29 +00:00
} goto loop;
case dup2: {
object first = stack[sp - 1];
2007-06-17 22:03:27 +00:00
if (isLongOrDouble(t, first)) {
push(t, first);
2007-05-22 00:05:29 +00:00
} else {
object second = stack[sp - 2];
push(t, second);
push(t, first);
2007-05-22 00:05:29 +00:00
}
} goto loop;
case dup2_x1: {
object first = pop(t);
object second = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-17 22:03:27 +00:00
if (isLongOrDouble(t, first)) {
push(t, first);
push(t, second);
push(t, first);
2007-05-22 00:05:29 +00:00
} else {
object third = pop(t);
push(t, second);
push(t, first);
push(t, third);
push(t, second);
push(t, first);
2007-05-22 00:05:29 +00:00
}
} goto loop;
case dup2_x2: {
object first = pop(t);
object second = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-17 22:03:27 +00:00
if (isLongOrDouble(t, first)) {
if (isLongOrDouble(t, second)) {
push(t, first);
push(t, second);
push(t, first);
2007-05-22 00:05:29 +00:00
} else {
object third = pop(t);
push(t, first);
push(t, third);
push(t, second);
push(t, first);
2007-05-22 00:05:29 +00:00
}
} else {
object third = pop(t);
2007-06-17 22:03:27 +00:00
if (isLongOrDouble(t, third)) {
push(t, second);
push(t, first);
push(t, third);
push(t, second);
push(t, first);
2007-05-22 00:05:29 +00:00
} else {
object fourth = pop(t);
push(t, second);
push(t, first);
push(t, fourth);
push(t, third);
push(t, second);
push(t, first);
2007-05-22 00:05:29 +00:00
}
}
} goto loop;
case getfield: {
object instance = pop(t);
if (LIKELY(instance)) {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
uint16_t index = (index1 << 8) | index2;
object field = resolveField(t, codePool(t, code), index);
if (UNLIKELY(exception)) goto throw_;
2007-05-22 00:05:29 +00:00
push(t, getField(t, instance, field));
2007-05-22 00:05:29 +00:00
} else {
exception = makeNullPointerException(t);
2007-05-22 00:05:29 +00:00
goto throw_;
}
} goto loop;
case getstatic: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
uint16_t index = (index1 << 8) | index2;
2007-05-25 14:48:07 +00:00
object field = resolveField(t, codePool(t, code), index);
if (UNLIKELY(exception)) goto throw_;
2007-05-25 14:48:07 +00:00
2007-06-17 23:25:58 +00:00
object clinit = classInitializer(t, fieldClass(t, field));
if (clinit) {
set(t, classInitializer(t, fieldClass(t, field)), 0);
code = clinit;
ip -= 3;
parameterCount = 0;
goto invoke;
2007-05-22 00:05:29 +00:00
}
push(t, getStatic(t, field));
2007-05-22 00:05:29 +00:00
} goto loop;
case goto_: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
} goto loop;
case goto_w: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
uint8_t offset3 = codeBody(t, code)[ip++];
uint8_t offset4 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
ip = (ip - 1)
+ ((offset1 << 24) | (offset2 << 16) | (offset3 << 8) | offset4);
} goto loop;
case i2b: {
object v = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, static_cast<int8_t>(intValue(t, v))));
2007-05-22 00:05:29 +00:00
} goto loop;
case i2c: {
object v = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, static_cast<uint16_t>(intValue(t, v))));
2007-05-22 00:05:29 +00:00
} goto loop;
case i2l: {
object v = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeLong(t, intValue(t, v)));
2007-05-22 00:05:29 +00:00
} goto loop;
case i2s: {
object v = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, static_cast<int16_t>(intValue(t, v))));
2007-05-22 00:05:29 +00:00
} goto loop;
case iadd: {
object b = pop(t);
object a = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, intValue(t, a) + intValue(t, b)));
2007-05-22 00:05:29 +00:00
} goto loop;
case iaload: {
object index = pop(t);
object array = pop(t);
2007-05-22 00:05:29 +00:00
if (LIKELY(array)) {
2007-06-05 00:28:52 +00:00
int32_t i = intValue(t, index);
if (LIKELY(i >= 0 and
static_cast<uint32_t>(i) < intArrayLength(t, array)))
{
2007-06-06 00:41:04 +00:00
push(t, makeInt(t, intArrayBody(t, array)[i]));
2007-05-22 00:05:29 +00:00
} else {
object message = makeString(t, "%d not in [0,%d]", i,
intArrayLength(t, array));
exception = makeArrayIndexOutOfBoundsException(t, message);
2007-05-22 00:05:29 +00:00
goto throw_;
}
} else {
exception = makeNullPointerException(t);
2007-05-22 00:05:29 +00:00
goto throw_;
}
} goto loop;
case iand: {
object b = pop(t);
object a = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, intValue(t, a) & intValue(t, b)));
2007-05-22 00:05:29 +00:00
} goto loop;
case iastore: {
object value = pop(t);
object index = pop(t);
object array = pop(t);
2007-06-05 00:28:52 +00:00
int32_t i = intValue(t, index);
2007-05-22 00:05:29 +00:00
if (LIKELY(array)) {
if (LIKELY(i >= 0 and
static_cast<uint32_t>(i) < intArrayLength(t, array)))
{
2007-06-06 00:41:04 +00:00
intArrayBody(t, array)[i] = intValue(t, value);
2007-05-22 00:05:29 +00:00
} else {
object message = makeString(t, "%d not in [0,%d]", i,
intArrayLength(t, array));
exception = makeArrayIndexOutOfBoundsException(t, message);
2007-05-22 00:05:29 +00:00
goto throw_;
}
} else {
exception = makeNullPointerException(t);
2007-05-22 00:05:29 +00:00
goto throw_;
}
} goto loop;
case iconst_0: {
2007-06-06 00:41:04 +00:00
push(t, makeInt(t, 0));
2007-05-22 00:05:29 +00:00
} goto loop;
case iconst_1: {
2007-06-06 00:41:04 +00:00
push(t, makeInt(t, 1));
2007-05-22 00:05:29 +00:00
} goto loop;
case iconst_2: {
2007-06-06 00:41:04 +00:00
push(t, makeInt(t, 2));
2007-05-22 00:05:29 +00:00
} goto loop;
case iconst_3: {
2007-06-06 00:41:04 +00:00
push(t, makeInt(t, 3));
2007-05-22 00:05:29 +00:00
} goto loop;
case iconst_4: {
2007-06-06 00:41:04 +00:00
push(t, makeInt(t, 4));
2007-05-22 00:05:29 +00:00
} goto loop;
case iconst_5: {
2007-06-06 00:41:04 +00:00
push(t, makeInt(t, 5));
2007-05-22 00:05:29 +00:00
} goto loop;
case idiv: {
object b = pop(t);
object a = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, intValue(t, a) / intValue(t, b)));
2007-05-22 00:05:29 +00:00
} goto loop;
case if_acmpeq: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object b = pop(t);
object a = pop(t);
2007-05-22 00:05:29 +00:00
if (a == b) {
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case if_acmpne: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object b = pop(t);
object a = pop(t);
2007-05-22 00:05:29 +00:00
if (a != b) {
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case if_icmpeq: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object b = pop(t);
object a = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
if (intValue(t, a) == intValue(t, b)) {
2007-05-22 00:05:29 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case if_icmpne: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object b = pop(t);
object a = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
if (intValue(t, a) != intValue(t, b)) {
2007-05-22 00:05:29 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case if_icmpgt: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object b = pop(t);
object a = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
if (intValue(t, a) > intValue(t, b)) {
2007-05-22 00:05:29 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case if_icmpge: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object b = pop(t);
object a = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
if (intValue(t, a) >= intValue(t, b)) {
2007-05-22 00:05:29 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case if_icmplt: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object b = pop(t);
object a = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
if (intValue(t, a) < intValue(t, b)) {
2007-05-22 00:05:29 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case if_icmple: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object b = pop(t);
object a = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
if (intValue(t, a) < intValue(t, b)) {
2007-05-22 00:05:29 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case ifeq: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object v = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
if (intValue(t, v) == 0) {
2007-05-22 00:05:29 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case ifne: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object v = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
if (intValue(t, v)) {
2007-05-22 00:05:29 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case ifgt: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object v = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
if (intValue(t, v) > 0) {
2007-05-22 00:05:29 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case ifge: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object v = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
if (intValue(t, v) >= 0) {
2007-05-22 00:05:29 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case iflt: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object v = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
if (intValue(t, v) < 0) {
2007-05-22 00:05:29 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case ifle: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object v = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
if (intValue(t, v) <= 0) {
2007-05-22 00:05:29 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case ifnonnull: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object v = pop(t);
2007-05-22 00:05:29 +00:00
if (v) {
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case ifnull: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
object v = pop(t);
2007-05-22 00:05:29 +00:00
if (v == 0) {
ip = (ip - 1) + ((offset1 << 8) | offset2);
}
} goto loop;
case iinc: {
uint8_t index = codeBody(t, code)[ip++];
int8_t c = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
int32_t v = intValue(t, frameLocals(t, frame)[index]);
frameLocals(t, frame)[index] = makeInt(t, v + c);
2007-05-22 00:05:29 +00:00
} goto loop;
case imul: {
object b = pop(t);
object a = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, intValue(t, a) * intValue(t, b)));
2007-05-22 00:05:29 +00:00
} goto loop;
case ineg: {
object v = pop(t);
2007-05-22 00:05:29 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, - intValue(t, v)));
2007-05-22 00:05:29 +00:00
} goto loop;
case instanceof: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
2007-05-22 00:05:29 +00:00
if (stack[sp - 1]) {
2007-05-22 00:05:29 +00:00
uint16_t index = (index1 << 8) | index2;
object class_ = resolveClass(t, codePool(t, code), index);
if (UNLIKELY(exception)) goto throw_;
2007-05-22 00:05:29 +00:00
if (instanceOf(t, class_, stack[sp - 1])) {
push(t, makeInt(t, 1));
2007-05-22 00:05:29 +00:00
} else {
push(t, makeInt(t, 0));
2007-05-22 00:05:29 +00:00
}
} else {
push(t, makeInt(t, 0));
2007-05-22 00:05:29 +00:00
}
} goto loop;
2007-05-25 14:48:07 +00:00
case invokeinterface: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
2007-05-30 00:08:10 +00:00
uint16_t index = (index1 << 8) | index2;
ip += 2;
object method = resolveMethod(t, codePool(t, code), index);
if (UNLIKELY(exception)) goto throw_;
2007-05-30 00:08:10 +00:00
parameterCount = methodParameterCount(t, method);
if (LIKELY(stack[sp - parameterCount])) {
code = findInterfaceMethod(t, method, stack[sp - parameterCount]);
if (UNLIKELY(exception)) goto throw_;
2007-05-30 00:08:10 +00:00
goto invoke;
} else {
exception = makeNullPointerException(t);
2007-05-30 00:08:10 +00:00
goto throw_;
}
} goto loop;
case invokespecial: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
2007-05-30 00:08:10 +00:00
uint16_t index = (index1 << 8) | index2;
object method = resolveMethod(t, codePool(t, code), index);
if (UNLIKELY(exception)) goto throw_;
2007-05-30 00:08:10 +00:00
parameterCount = methodParameterCount(t, method);
if (LIKELY(stack[sp - parameterCount])) {
object class_ = methodClass(t, frameMethod(t, t->frame));
if (isSpecialMethod(t, method, class_)) {
code = findMethod(t, method, classSuper(t, class_));
if (UNLIKELY(exception)) goto throw_;
2007-05-30 00:08:10 +00:00
} else {
code = method;
2007-05-30 00:08:10 +00:00
}
goto invoke;
} else {
exception = makeNullPointerException(t);
2007-05-30 00:08:10 +00:00
goto throw_;
}
} goto loop;
case invokestatic: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
2007-05-30 00:08:10 +00:00
uint16_t index = (index1 << 8) | index2;
object method = resolveMethod(t, codePool(t, code), index);
if (UNLIKELY(exception)) goto throw_;
2007-05-30 00:08:10 +00:00
object clinit = classInitializer(t, methodClass(t, method));
2007-06-17 23:25:58 +00:00
if (clinit) {
set(t, classInitializer(t, methodClass(t, method)), 0);
2007-06-17 23:25:58 +00:00
code = clinit;
ip -= 3;
2007-05-30 00:08:10 +00:00
parameterCount = 0;
goto invoke;
}
parameterCount = methodParameterCount(t, method);
code = method;
2007-05-30 00:08:10 +00:00
} goto invoke;
case invokevirtual: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
2007-05-30 00:08:10 +00:00
uint16_t index = (index1 << 8) | index2;
object method = resolveMethod(t, codePool(t, code), index);
if (UNLIKELY(exception)) goto throw_;
2007-05-30 00:08:10 +00:00
parameterCount = methodParameterCount(t, method);
if (LIKELY(stack[sp - parameterCount])) {
code = findVirtualMethod(t, method, stack[sp - parameterCount]);
if (UNLIKELY(exception)) goto throw_;
2007-05-30 00:08:10 +00:00
goto invoke;
} else {
exception = makeNullPointerException(t);
2007-05-30 00:08:10 +00:00
goto throw_;
}
} goto loop;
case ior: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, intValue(t, a) | intValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case irem: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, intValue(t, a) % intValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case ishl: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, intValue(t, a) << intValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case ishr: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, intValue(t, a) >> intValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case isub: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, intValue(t, a) - intValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case iushr: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, static_cast<uint32_t>(intValue(t, a)) >> intValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case ixor: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-05 00:28:52 +00:00
push(t, makeInt(t, intValue(t, a) ^ intValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case jsr: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeInt(t, ip));
2007-05-30 00:08:10 +00:00
ip = (ip - 1) + ((offset1 << 8) | offset2);
} goto loop;
case jsr_w: {
uint8_t offset1 = codeBody(t, code)[ip++];
uint8_t offset2 = codeBody(t, code)[ip++];
uint8_t offset3 = codeBody(t, code)[ip++];
uint8_t offset4 = codeBody(t, code)[ip++];
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeInt(t, ip));
2007-05-30 00:08:10 +00:00
ip = (ip - 1)
+ ((offset1 << 24) | (offset2 << 16) | (offset3 << 8) | offset4);
} goto loop;
case l2i: {
object v = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeInt(t, static_cast<int32_t>(longValue(t, v))));
2007-05-30 00:08:10 +00:00
} goto loop;
case ladd: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, longValue(t, a) + longValue(t, b)));
2007-05-25 14:48:07 +00:00
} goto loop;
2007-05-30 00:08:10 +00:00
case laload: {
object index = pop(t);
object array = pop(t);
2007-05-30 00:08:10 +00:00
if (LIKELY(array)) {
2007-06-05 00:28:52 +00:00
int32_t i = intValue(t, index);
if (LIKELY(i >= 0 and
static_cast<uint32_t>(i) < longArrayLength(t, array)))
{
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, longArrayBody(t, array)[i]));
2007-05-30 00:08:10 +00:00
} else {
object message = makeString(t, "%d not in [0,%d]", i,
longArrayLength(t, array));
exception = makeArrayIndexOutOfBoundsException(t, message);
2007-05-30 00:08:10 +00:00
goto throw_;
}
} else {
exception = makeNullPointerException(t);
2007-05-30 00:08:10 +00:00
goto throw_;
}
} goto loop;
case land: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, longValue(t, a) & longValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case lastore: {
object value = pop(t);
object index = pop(t);
object array = pop(t);
2007-06-05 00:28:52 +00:00
int32_t i = intValue(t, index);
2007-05-30 00:08:10 +00:00
if (LIKELY(array)) {
if (LIKELY(i >= 0 and
static_cast<uint32_t>(i) < longArrayLength(t, array)))
{
2007-06-06 00:41:04 +00:00
longArrayBody(t, array)[i] = longValue(t, value);
2007-05-30 00:08:10 +00:00
} else {
object message = makeString(t, "%d not in [0,%d]", i,
longArrayLength(t, array));
exception = makeArrayIndexOutOfBoundsException(t, message);
2007-05-30 00:08:10 +00:00
goto throw_;
}
} else {
exception = makeNullPointerException(t);
2007-05-30 00:08:10 +00:00
goto throw_;
}
} goto loop;
case lcmp: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeInt(t, longValue(t, a) > longValue(t, b) ? 1
: longValue(t, a) == longValue(t, b) ? 0 : -1));
2007-05-30 00:08:10 +00:00
} goto loop;
case lconst_0: {
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, 0));
2007-05-30 00:08:10 +00:00
} goto loop;
case lconst_1: {
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, 1));
2007-05-30 00:08:10 +00:00
} goto loop;
case ldc: {
2007-06-17 22:03:27 +00:00
push(t, arrayBody(t, codePool(t, code))[codeBody(t, code)[ip++]]);
2007-05-30 00:08:10 +00:00
} goto loop;
case ldc_w:
case ldc2_w: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
2007-05-30 00:08:10 +00:00
2007-06-17 22:03:27 +00:00
push(t, arrayBody(t, codePool(t, code))[(index1 << 8) | index2]);
2007-05-30 00:08:10 +00:00
} goto loop;
case vm::ldiv: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, longValue(t, a) / longValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case lmul: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, longValue(t, a) * longValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case lneg: {
object v = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, - longValue(t, v)));
2007-05-30 00:08:10 +00:00
} goto loop;
case lor: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, longValue(t, a) | longValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case lrem: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, longValue(t, a) % longValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case lshl: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, longValue(t, a) << longValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case lshr: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, longValue(t, a) >> longValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case lsub: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, longValue(t, a) - longValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case lushr: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, static_cast<uint64_t>(longValue(t, a))
<< longValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case lxor: {
object b = pop(t);
object a = pop(t);
2007-05-30 00:08:10 +00:00
2007-06-06 00:41:04 +00:00
push(t, makeLong(t, longValue(t, a) ^ longValue(t, b)));
2007-05-30 00:08:10 +00:00
} goto loop;
case new_: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
uint16_t index = (index1 << 8) | index2;
object class_ = resolveClass(t, codePool(t, code), index);
if (UNLIKELY(exception)) goto throw_;
object clinit = classInitializer(t, class_);
2007-06-17 23:25:58 +00:00
if (clinit) {
set(t, classInitializer(t, class_), 0);
2007-06-17 23:25:58 +00:00
code = clinit;
ip -= 3;
parameterCount = 0;
goto invoke;
}
push(t, make(t, class_));
} goto loop;
case newarray: {
object count = pop(t);
2007-06-05 00:28:52 +00:00
int32_t c = intValue(t, count);
if (LIKELY(c >= 0)) {
uint8_t type = codeBody(t, code)[ip++];
object array;
unsigned factor;
switch (type) {
case T_BOOLEAN:
array = makeBooleanArray(t, c);
factor = 1;
break;
case T_CHAR:
array = makeCharArray(t, c);
factor = 2;
break;
case T_FLOAT:
array = makeFloatArray(t, c);
factor = 4;
break;
case T_DOUBLE:
array = makeDoubleArray(t, c);
factor = 8;
break;
case T_BYTE:
array = makeByteArray(t, c);
factor = 1;
break;
case T_SHORT:
array = makeShortArray(t, c);
factor = 2;
break;
case T_INT:
array = makeIntArray(t, c);
factor = 4;
break;
case T_LONG:
array = makeLongArray(t, c);
factor = 8;
break;
default: abort(t);
}
2007-06-09 02:33:26 +00:00
memset(static_cast<uint8_t*>(array) + sizeof(object) + 4, 0,
c * factor);
push(t, array);
} else {
object message = makeString(t, "%d", c);
exception = makeNegativeArrayStoreException(t, message);
goto throw_;
}
} goto loop;
case nop: goto loop;
case vm::pop: {
-- sp;
} goto loop;
case pop2: {
object top = stack[sp - 1];
2007-06-17 22:03:27 +00:00
if (isLongOrDouble(t, top)) {
-- sp;
} else {
sp -= 2;
}
} goto loop;
case putfield: {
object instance = pop(t);
if (LIKELY(instance)) {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
uint16_t index = (index1 << 8) | index2;
object field = resolveField(t, codePool(t, code), index);
if (UNLIKELY(exception)) goto throw_;
object value = pop(t);
setField(t, instance, field, value);
} else {
exception = makeNullPointerException(t);
goto throw_;
}
} goto loop;
case putstatic: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
uint16_t index = (index1 << 8) | index2;
object field = resolveField(t, codePool(t, code), index);
if (UNLIKELY(exception)) goto throw_;
2007-06-17 23:25:58 +00:00
object clinit = classInitializer(t, fieldClass(t, field));
if (clinit) {
set(t, classInitializer(t, fieldClass(t, field)), 0);
code = clinit;
ip -= 3;
parameterCount = 0;
goto invoke;
}
object value = pop(t);
setStatic(t, field, value);
} goto loop;
case ret: {
ip = intValue(t, frameLocals(t, frame)[codeBody(t, code)[ip]]);
} goto loop;
case return_: {
frame = frameNext(t, frame);
if (frame) {
code = methodCode(t, frameMethod(t, frame));
ip = frameIp(t, frame);
goto loop;
} else {
code = 0;
return 0;
}
} goto loop;
case saload: {
object index = pop(t);
object array = pop(t);
if (LIKELY(array)) {
2007-06-05 00:28:52 +00:00
int32_t i = intValue(t, index);
if (LIKELY(i >= 0 and
static_cast<uint32_t>(i) < shortArrayLength(t, array)))
{
2007-06-06 00:41:04 +00:00
push(t, makeShort(t, shortArrayBody(t, array)[i]));
} else {
object message = makeString(t, "%d not in [0,%d]", i,
shortArrayLength(t, array));
exception = makeArrayIndexOutOfBoundsException(t, message);
goto throw_;
}
} else {
exception = makeNullPointerException(t);
goto throw_;
}
} goto loop;
case sastore: {
object value = pop(t);
object index = pop(t);
object array = pop(t);
2007-06-05 00:28:52 +00:00
int32_t i = intValue(t, index);
if (LIKELY(array)) {
if (LIKELY(i >= 0 and
static_cast<uint32_t>(i) < shortArrayLength(t, array)))
{
2007-06-06 00:41:04 +00:00
shortArrayBody(t, array)[i] = intValue(t, value);
} else {
object message = makeString(t, "%d not in [0,%d]", i,
shortArrayLength(t, array));
exception = makeArrayIndexOutOfBoundsException(t, message);
goto throw_;
}
} else {
exception = makeNullPointerException(t);
goto throw_;
}
} goto loop;
case sipush: {
uint8_t byte1 = codeBody(t, code)[ip++];
uint8_t byte2 = codeBody(t, code)[ip++];
push(t, makeInt(t, (byte1 << 8) | byte2));
} goto loop;
case swap: {
object tmp = stack[sp - 1];
stack[sp - 1] = stack[sp - 2];
stack[sp - 2] = tmp;
} goto loop;
case wide: goto wide;
default: abort(t);
}
wide:
switch (codeBody(t, code)[ip++]) {
case aload:
case iload:
case lload: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
push(t, frameLocals(t, frame)[(index1 << 8) | index2]);
} goto loop;
case astore:
case istore:
case lstore: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
object value = pop(t);
set(t, frameLocals(t, frame)[(index1 << 8) | index2], value);
} goto loop;
case iinc: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
uint16_t index = (index1 << 8) | index2;
uint8_t count1 = codeBody(t, code)[ip++];
uint8_t count2 = codeBody(t, code)[ip++];
uint16_t count = (count1 << 8) | count2;
int32_t v = intValue(t, frameLocals(t, frame)[index]);
frameLocals(t, frame)[index] = makeInt(t, v + count);
} goto loop;
case ret: {
uint8_t index1 = codeBody(t, code)[ip++];
uint8_t index2 = codeBody(t, code)[ip++];
ip = intValue(t, frameLocals(t, frame)[(index1 << 8) | index2]);
2007-05-30 00:08:10 +00:00
} goto loop;
default: abort(t);
2007-05-30 00:08:10 +00:00
}
invoke:
if (UNLIKELY(codeMaxStack(t, methodCode(t, code)) + sp - parameterCount
> Thread::StackSize))
2007-06-06 02:24:09 +00:00
{
exception = makeStackOverflowError(t);
2007-05-30 00:08:10 +00:00
goto throw_;
2007-05-21 15:47:44 +00:00
}
2007-05-30 00:08:10 +00:00
frameIp(t, frame) = ip;
2007-05-30 00:08:10 +00:00
sp -= parameterCount;
frame = makeFrame(t, code, frame, 0, sp,
codeMaxLocals(t, methodCode(t, code)));
memcpy(frameLocals(t, frame), stack + sp, parameterCount);
2007-05-30 00:08:10 +00:00
ip = 0;
goto loop;
2007-05-21 15:47:44 +00:00
throw_:
for (; frame; frame = frameNext(t, frame)) {
code = methodCode(t, frameMethod(t, frame));
object eht = codeExceptionHandlerTable(t, code);
2007-05-25 14:48:07 +00:00
if (eht) {
2007-06-06 02:24:09 +00:00
for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) {
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
2007-05-25 14:48:07 +00:00
uint16_t catchType = exceptionHandlerCatchType(eh);
if (catchType == 0 or
instanceOf(t,
2007-06-17 22:03:27 +00:00
arrayBody(t, codePool(t, code))[catchType],
exception))
2007-05-25 14:48:07 +00:00
{
sp = frameStackBase(t, frame);
2007-05-25 14:48:07 +00:00
ip = exceptionHandlerIp(eh);
push(t, exception);
exception = 0;
2007-05-25 14:48:07 +00:00
goto loop;
2007-05-21 15:47:44 +00:00
}
}
}
}
object method = threadExceptionHandler(t, t->thread);
code = methodCode(t, method);
frame = makeFrame(t, method, 0, 0, 0, codeMaxLocals(t, code));
sp = 0;
2007-05-21 15:47:44 +00:00
ip = 0;
push(t, exception);
exception = 0;
2007-05-21 15:47:44 +00:00
goto loop;
}
} // namespace