2007-06-03 02:00:23 +00:00
|
|
|
#include "common.h"
|
|
|
|
#include "system.h"
|
|
|
|
#include "heap.h"
|
2007-06-25 02:02:24 +00:00
|
|
|
#include "class-finder.h"
|
2007-06-16 01:02:24 +00:00
|
|
|
#include "stream.h"
|
2007-06-18 19:23:44 +00:00
|
|
|
#include "constants.h"
|
2007-06-25 02:02:24 +00:00
|
|
|
#include "jni-vm.h"
|
2007-06-18 21:13:21 +00:00
|
|
|
#include "vm.h"
|
2007-06-03 02:00:23 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
#define PROTECT(thread, name) \
|
|
|
|
Thread::Protector MAKE_NAME(protector_) (thread, &name);
|
2007-06-07 00:30:16 +00:00
|
|
|
|
2007-06-15 00:50:55 +00:00
|
|
|
#define ACQUIRE(t, x) MonitorResource MAKE_NAME(monitorResource_) (t, x)
|
2007-07-02 01:42:35 +00:00
|
|
|
|
2007-06-15 00:50:55 +00:00
|
|
|
#define ACQUIRE_RAW(t, x) RawMonitorResource MAKE_NAME(monitorResource_) (t, x)
|
2007-06-14 23:55:06 +00:00
|
|
|
|
2007-07-02 01:42:35 +00:00
|
|
|
#define ENTER(t, state) StateResource MAKE_NAME(stateResource_) (t, state)
|
|
|
|
|
2007-06-18 19:23:44 +00:00
|
|
|
using namespace vm;
|
|
|
|
|
2007-05-21 15:47:44 +00:00
|
|
|
namespace {
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
const bool Verbose = false;
|
2007-07-02 01:42:35 +00:00
|
|
|
const bool Debug = false;
|
2007-07-04 17:58:27 +00:00
|
|
|
const bool DebugRun = false;
|
|
|
|
const bool DebugStack = false;
|
2007-07-02 01:42:35 +00:00
|
|
|
|
|
|
|
const uintptr_t HashTakenMark = 1;
|
|
|
|
const uintptr_t ExtendedMark = 2;
|
2007-06-21 01:38:02 +00:00
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
const unsigned FrameBaseOffset = 0;
|
|
|
|
const unsigned FrameNextOffset = 1;
|
|
|
|
const unsigned FrameMethodOffset = 2;
|
|
|
|
const unsigned FrameIpOffset = 3;
|
|
|
|
const unsigned FrameFootprint = 4;
|
|
|
|
|
2007-06-03 02:00:23 +00:00
|
|
|
class Thread;
|
|
|
|
|
2007-06-24 01:39:49 +00:00
|
|
|
void (*Initializer)(Thread*, object);
|
|
|
|
|
2007-06-18 04:09:02 +00:00
|
|
|
void assert(Thread*, bool);
|
2007-06-24 19:57:00 +00:00
|
|
|
void expect(Thread*, bool);
|
2007-06-18 04:09:02 +00:00
|
|
|
object resolveClass(Thread*, object);
|
2007-06-18 21:13:21 +00:00
|
|
|
object allocate(Thread*, unsigned);
|
2007-06-21 18:35:24 +00:00
|
|
|
object& arrayBodyUnsafe(Thread*, object, unsigned);
|
2007-06-18 21:13:21 +00:00
|
|
|
void set(Thread*, object&, object);
|
2007-06-24 21:49:04 +00:00
|
|
|
object makeString(Thread*, const char*, ...);
|
2007-06-24 19:57:00 +00:00
|
|
|
object makeByteArray(Thread*, const char*, ...);
|
2007-06-18 19:23:44 +00:00
|
|
|
|
2007-06-24 01:39:49 +00:00
|
|
|
enum FieldCode {
|
2007-06-24 21:49:04 +00:00
|
|
|
VoidField,
|
2007-06-24 01:39:49 +00:00
|
|
|
ByteField,
|
|
|
|
CharField,
|
|
|
|
DoubleField,
|
|
|
|
FloatField,
|
|
|
|
IntField,
|
|
|
|
LongField,
|
|
|
|
ShortField,
|
|
|
|
BooleanField,
|
|
|
|
ObjectField
|
|
|
|
};
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
enum StackTag {
|
|
|
|
IntTag, // must be zero
|
|
|
|
ObjectTag
|
|
|
|
};
|
|
|
|
|
2007-07-04 15:56:55 +00:00
|
|
|
const int NativeLine = -1;
|
|
|
|
const int UnknownLine = -2;
|
|
|
|
|
|
|
|
const unsigned WeakReferenceFlag = 1 << 0;
|
2007-06-30 01:37:45 +00:00
|
|
|
|
2007-06-03 02:00:23 +00:00
|
|
|
class Machine {
|
|
|
|
public:
|
2007-06-18 21:13:21 +00:00
|
|
|
enum {
|
|
|
|
#include "type-enums.cpp"
|
|
|
|
} Type;
|
|
|
|
|
2007-06-20 16:58:35 +00:00
|
|
|
Machine(System* system, Heap* heap, ClassFinder* classFinder);
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
~Machine() {
|
|
|
|
dispose();
|
|
|
|
}
|
|
|
|
|
2007-06-22 22:47:57 +00:00
|
|
|
void dispose();
|
2007-06-20 17:42:13 +00:00
|
|
|
|
|
|
|
System* system;
|
2007-06-03 02:00:23 +00:00
|
|
|
Heap* heap;
|
2007-06-14 23:55:06 +00:00
|
|
|
ClassFinder* classFinder;
|
2007-06-03 02:00:23 +00:00
|
|
|
Thread* rootThread;
|
|
|
|
Thread* exclusive;
|
|
|
|
unsigned activeCount;
|
|
|
|
unsigned liveCount;
|
|
|
|
System::Monitor* stateLock;
|
2007-06-08 14:23:04 +00:00
|
|
|
System::Monitor* heapLock;
|
2007-06-14 23:55:06 +00:00
|
|
|
System::Monitor* classLock;
|
2007-07-02 14:19:05 +00:00
|
|
|
System::Monitor* finalizerLock;
|
2007-06-24 19:57:00 +00:00
|
|
|
System::Library* libraries;
|
2007-06-14 23:55:06 +00:00
|
|
|
object classMap;
|
2007-06-24 19:57:00 +00:00
|
|
|
object bootstrapClassMap;
|
2007-06-24 21:49:04 +00:00
|
|
|
object builtinMap;
|
2007-07-02 01:42:35 +00:00
|
|
|
object monitorMap;
|
2007-06-18 21:13:21 +00:00
|
|
|
object types;
|
2007-07-02 14:19:05 +00:00
|
|
|
object finalizers;
|
|
|
|
object doomed;
|
2007-07-04 15:56:55 +00:00
|
|
|
object weakReferences;
|
2007-06-21 18:35:24 +00:00
|
|
|
bool unsafe;
|
2007-06-25 02:02:24 +00:00
|
|
|
JNIEnvVTable jniEnvVTable;
|
2007-06-03 02:00:23 +00:00
|
|
|
};
|
|
|
|
|
2007-06-22 22:47:57 +00:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2007-06-25 02:02:24 +00:00
|
|
|
class Thread : public JNIEnv {
|
2007-06-03 02:00:23 +00:00
|
|
|
public:
|
|
|
|
enum State {
|
|
|
|
NoState,
|
|
|
|
ActiveState,
|
|
|
|
IdleState,
|
|
|
|
ZombieState,
|
|
|
|
ExclusiveState,
|
|
|
|
ExitState
|
|
|
|
};
|
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2007-06-22 20:55:11 +00:00
|
|
|
static const unsigned HeapSizeInBytes = 64 * 1024;
|
|
|
|
static const unsigned StackSizeInBytes = 64 * 1024;
|
2007-06-03 02:00:23 +00:00
|
|
|
|
2007-06-22 21:31:45 +00:00
|
|
|
static const unsigned HeapSizeInWords = HeapSizeInBytes / BytesPerWord;
|
|
|
|
static const unsigned StackSizeInWords = StackSizeInBytes / BytesPerWord;
|
|
|
|
|
2007-06-20 17:42:13 +00:00
|
|
|
Thread(Machine* m);
|
|
|
|
|
2007-06-22 22:47:57 +00:00
|
|
|
void dispose();
|
|
|
|
|
2007-06-03 02:00:23 +00:00
|
|
|
Machine* vm;
|
|
|
|
Thread* next;
|
|
|
|
Thread* child;
|
|
|
|
State state;
|
2007-06-13 14:03:08 +00:00
|
|
|
object thread;
|
2007-06-03 02:00:23 +00:00
|
|
|
object code;
|
|
|
|
object exception;
|
2007-06-08 14:23:04 +00:00
|
|
|
unsigned ip;
|
2007-06-03 02:00:23 +00:00
|
|
|
unsigned sp;
|
2007-07-06 01:06:06 +00:00
|
|
|
int frame;
|
2007-06-03 02:00:23 +00:00
|
|
|
unsigned heapIndex;
|
2007-06-08 00:23:12 +00:00
|
|
|
Protector* protector;
|
2007-06-22 22:47:57 +00:00
|
|
|
Chain* chain;
|
2007-07-04 02:56:02 +00:00
|
|
|
uintptr_t stack[StackSizeInWords];
|
2007-06-25 01:34:07 +00:00
|
|
|
object heap[HeapSizeInWords];
|
2007-06-03 02:00:23 +00:00
|
|
|
};
|
|
|
|
|
2007-07-01 21:34:22 +00:00
|
|
|
inline object
|
|
|
|
objectClass(Thread*, object o)
|
|
|
|
{
|
|
|
|
return mask(cast<object>(o, 0));
|
|
|
|
}
|
|
|
|
|
2007-06-18 19:23:44 +00:00
|
|
|
#include "type-declarations.cpp"
|
|
|
|
#include "type-constructors.cpp"
|
2007-06-18 04:09:02 +00:00
|
|
|
|
2007-06-15 00:50:55 +00:00
|
|
|
void enter(Thread* t, Thread::State state);
|
|
|
|
|
2007-07-02 01:42:35 +00:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2007-06-14 23:55:06 +00:00
|
|
|
class MonitorResource {
|
|
|
|
public:
|
2007-06-15 00:50:55 +00:00
|
|
|
MonitorResource(Thread* t, System::Monitor* m): t(t), m(m) {
|
|
|
|
if (not m->tryAcquire(t)) {
|
2007-07-02 01:42:35 +00:00
|
|
|
ENTER(t, Thread::IdleState);
|
2007-06-15 00:50:55 +00:00
|
|
|
m->acquire(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~MonitorResource() { m->release(t); }
|
2007-06-14 23:55:06 +00:00
|
|
|
|
|
|
|
private:
|
2007-06-15 00:50:55 +00:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2007-06-03 02:00:23 +00:00
|
|
|
inline void NO_RETURN
|
|
|
|
abort(Thread* t)
|
|
|
|
{
|
2007-06-22 23:17:13 +00:00
|
|
|
abort(t->vm->system);
|
2007-06-03 02:00:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
assert(Thread* t, bool v)
|
|
|
|
{
|
2007-06-22 23:17:13 +00:00
|
|
|
assert(t->vm->system, v);
|
2007-06-03 02:00:23 +00:00
|
|
|
}
|
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
inline void
|
|
|
|
expect(Thread* t, bool v)
|
|
|
|
{
|
|
|
|
expect(t->vm->system, v);
|
|
|
|
}
|
|
|
|
|
|
|
|
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-07-02 01:42:35 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
extendedSize(Thread* t, object o, unsigned baseSize)
|
|
|
|
{
|
2007-07-02 14:19:05 +00:00
|
|
|
return baseSize + objectExtended(t, o);
|
2007-07-02 01:42:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)) {
|
2007-07-02 14:19:05 +00:00
|
|
|
return extendedWord(t, o, baseSize(t, o, objectClass(t, o)));
|
2007-07-02 01:42:35 +00:00
|
|
|
} else {
|
|
|
|
markHashTaken(t, o);
|
|
|
|
return takeHash(t, o);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
objectEqual(Thread*, object a, object b)
|
|
|
|
{
|
|
|
|
return a == b;
|
|
|
|
}
|
|
|
|
|
2007-07-04 15:56:55 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
inline uint32_t
|
|
|
|
byteArrayHash(Thread* t, object array)
|
|
|
|
{
|
|
|
|
return hash(&byteArrayBody(t, array, 0), byteArrayLength(t, array));
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
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))
|
|
|
|
{
|
|
|
|
object array = hashMapArray(t, map);
|
|
|
|
if (array) {
|
|
|
|
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
|
|
|
|
object n = arrayBody(t, array, index);
|
|
|
|
while (n) {
|
2007-07-04 15:56:55 +00:00
|
|
|
if (equal(t, key, tripleFirst(t, n))) {
|
2007-06-24 19:57:00 +00:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = tripleThird(t, n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2007-07-02 14:19:05 +00:00
|
|
|
hashMapResize(Thread* t, object map, uint32_t (*hash)(Thread*, object),
|
|
|
|
unsigned size)
|
2007-06-24 19:57:00 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, map);
|
|
|
|
|
|
|
|
object oldArray = hashMapArray(t, map);
|
|
|
|
unsigned oldLength = (oldArray ? arrayLength(t, oldArray) : 0);
|
|
|
|
PROTECT(t, oldArray);
|
|
|
|
|
2007-07-04 17:58:27 +00:00
|
|
|
unsigned newLength = nextPowerOfTwo(size);
|
2007-06-24 19:57:00 +00:00
|
|
|
object newArray = makeArray(t, newLength, true);
|
|
|
|
|
|
|
|
if (oldArray) {
|
|
|
|
for (unsigned i = 0; i < oldLength; ++i) {
|
|
|
|
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-07-04 17:58:27 +00:00
|
|
|
hashMapResize(t, map, hash, array ? arrayLength(t, array) * 2 : 16);
|
2007-06-24 19:57:00 +00:00
|
|
|
array = hashMapArray(t, map);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
|
|
|
|
object n = arrayBody(t, array, index);
|
|
|
|
|
|
|
|
n = makeTriple(t, key, value, n);
|
|
|
|
|
|
|
|
set(t, arrayBody(t, array, index), n);
|
|
|
|
}
|
|
|
|
|
2007-07-05 02:25:25 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
object
|
|
|
|
hashMapRemove(Thread* t, object map, object key,
|
|
|
|
uint32_t (*hash)(Thread*, object),
|
|
|
|
bool (*equal)(Thread*, object, object))
|
|
|
|
{
|
|
|
|
object array = hashMapArray(t, map);
|
|
|
|
object o = 0;
|
|
|
|
if (array) {
|
|
|
|
unsigned index = hash(t, key) & (arrayLength(t, array) - 1);
|
|
|
|
object n = arrayBody(t, array, index);
|
|
|
|
object p = 0;
|
|
|
|
while (n) {
|
2007-07-04 15:56:55 +00:00
|
|
|
if (equal(t, key, tripleFirst(t, n))) {
|
2007-07-02 14:19:05 +00:00
|
|
|
o = tripleFirst(t, n);
|
|
|
|
if (p) {
|
|
|
|
set(t, tripleThird(t, p), tripleThird(t, n));
|
|
|
|
} else {
|
|
|
|
set(t, arrayBody(t, array, index), tripleThird(t, n));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
p = n;
|
|
|
|
n = tripleThird(t, n);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hashMapSize(t, map) <= arrayLength(t, array) / 3) {
|
|
|
|
hashMapResize(t, map, hash, arrayLength(t, array) / 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
return o;
|
|
|
|
}
|
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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-24 21:49:04 +00:00
|
|
|
inline void
|
2007-07-04 02:56:02 +00:00
|
|
|
pushObject(Thread* t, object o)
|
|
|
|
{
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
|
|
|
fprintf(stderr, "push object %p at %d\n", o, t->sp);
|
|
|
|
}
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
assert(t, t->sp + 1 < Thread::StackSizeInWords / 2);
|
2007-07-04 02:56:02 +00:00
|
|
|
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)
|
2007-06-24 21:49:04 +00:00
|
|
|
{
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
|
|
|
fprintf(stderr, "push int %d at %d\n", v, t->sp);
|
|
|
|
}
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
assert(t, t->sp + 1 < Thread::StackSizeInWords / 2);
|
2007-07-04 02:56:02 +00:00
|
|
|
t->stack[(t->sp * 2) ] = IntTag;
|
|
|
|
t->stack[(t->sp * 2) + 1] = v;
|
|
|
|
++ t->sp;
|
2007-06-24 21:49:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(Thread* t, uint64_t v)
|
2007-06-24 21:49:04 +00:00
|
|
|
{
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
2007-07-06 01:06:06 +00:00
|
|
|
fprintf(stderr, "push long " LLD " at %d\n", v, t->sp);
|
2007-07-04 17:58:27 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, v >> 32);
|
|
|
|
pushInt(t, v & 0xFF);
|
2007-06-24 21:49:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
2007-07-04 02:56:02 +00:00
|
|
|
popObject(Thread* t)
|
|
|
|
{
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
|
|
|
fprintf(stderr, "pop object %p at %d\n",
|
|
|
|
reinterpret_cast<object>(t->stack[((t->sp - 1) * 2) + 1]),
|
|
|
|
t->sp - 1);
|
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
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)
|
2007-06-24 21:49:04 +00:00
|
|
|
{
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
2007-07-06 01:06:06 +00:00
|
|
|
fprintf(stderr, "pop int " LD " at %d\n",
|
2007-07-04 17:58:27 +00:00
|
|
|
t->stack[((t->sp - 1) * 2) + 1],
|
|
|
|
t->sp - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(t, t->stack[(t->sp - 1) * 2] == IntTag);
|
2007-07-04 02:56:02 +00:00
|
|
|
return t->stack[((-- t->sp) * 2) + 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
inline uint64_t
|
|
|
|
popLong(Thread* t)
|
|
|
|
{
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
2007-07-06 01:06:06 +00:00
|
|
|
fprintf(stderr, "pop long " LLD " at %d\n",
|
2007-07-04 17:58:27 +00:00
|
|
|
(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);
|
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
uint64_t a = popInt(t);
|
|
|
|
uint64_t b = popInt(t);
|
|
|
|
return (b << 32) | a;
|
2007-06-24 21:49:04 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 17:58:27 +00:00
|
|
|
inline object
|
2007-07-04 02:56:02 +00:00
|
|
|
peekObject(Thread* t, unsigned index)
|
|
|
|
{
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
|
|
|
fprintf(stderr, "peek object %p at %d\n",
|
|
|
|
reinterpret_cast<object>(t->stack[(index * 2) + 1]),
|
|
|
|
index);
|
|
|
|
}
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
assert(t, index < Thread::StackSizeInWords / 2);
|
2007-07-04 02:56:02 +00:00
|
|
|
assert(t, t->stack[index * 2] == ObjectTag);
|
|
|
|
return *reinterpret_cast<object*>(t->stack + (index * 2) + 1);
|
|
|
|
}
|
|
|
|
|
2007-07-04 17:58:27 +00:00
|
|
|
inline uint32_t
|
2007-07-04 02:56:02 +00:00
|
|
|
peekInt(Thread* t, unsigned index)
|
|
|
|
{
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
2007-07-06 01:06:06 +00:00
|
|
|
fprintf(stderr, "peek int " LD " at %d\n",
|
2007-07-04 17:58:27 +00:00
|
|
|
t->stack[(index * 2) + 1],
|
|
|
|
index);
|
|
|
|
}
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
assert(t, index < Thread::StackSizeInWords / 2);
|
2007-07-04 02:56:02 +00:00
|
|
|
assert(t, t->stack[index * 2] == IntTag);
|
|
|
|
return t->stack[(index * 2) + 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
inline uint64_t
|
|
|
|
peekLong(Thread* t, unsigned index)
|
2007-06-24 21:49:04 +00:00
|
|
|
{
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
2007-07-06 01:06:06 +00:00
|
|
|
fprintf(stderr, "peek long " LLD " at %d\n",
|
2007-07-04 17:58:27 +00:00
|
|
|
(static_cast<uint64_t>(t->stack[(index * 2) + 1]) << 32)
|
|
|
|
| static_cast<uint64_t>(t->stack[((index + 1) * 2) + 1]),
|
|
|
|
index);
|
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
return (static_cast<uint64_t>(peekInt(t, index)) << 32)
|
2007-07-04 17:58:27 +00:00
|
|
|
| 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);
|
2007-07-04 02:56:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2007-07-04 17:58:27 +00:00
|
|
|
pokeInt(Thread* t, unsigned index, uint32_t value)
|
2007-07-04 02:56:02 +00:00
|
|
|
{
|
2007-07-04 17:58:27 +00:00
|
|
|
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) {
|
2007-07-06 01:06:06 +00:00
|
|
|
fprintf(stderr, "poke long " LLD " at %d\n", value, index);
|
2007-07-04 17:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pokeInt(t, index, value >> 32);
|
|
|
|
pokeInt(t, index + 2, value & 0xFF);
|
2007-07-04 02:56:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline object*
|
|
|
|
pushReference(Thread* t, object o)
|
|
|
|
{
|
|
|
|
expect(t, t->sp + 1 < Thread::StackSizeInWords / 2);
|
|
|
|
pushObject(t, o);
|
2007-07-04 17:58:27 +00:00
|
|
|
return reinterpret_cast<object*>(t->stack + ((t->sp - 1) * 2) + 1);
|
2007-06-24 21:49:04 +00:00
|
|
|
}
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pushFrame(Thread* t, object method)
|
|
|
|
{
|
|
|
|
if (t->frame >= 0) {
|
|
|
|
pokeInt(t, t->frame + FrameIpOffset, t->ip);
|
|
|
|
}
|
|
|
|
t->ip = 0;
|
|
|
|
|
|
|
|
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
|
|
|
unsigned base = t->sp - parameterFootprint;
|
|
|
|
unsigned locals = parameterFootprint;
|
|
|
|
|
|
|
|
if ((methodFlags(t, method) & ACC_NATIVE) == 0) {
|
|
|
|
t->code = methodCode(t, method);
|
|
|
|
|
|
|
|
locals = codeMaxLocals(t, t->code);
|
|
|
|
|
|
|
|
memset(t->stack + ((base + parameterFootprint) * 2), 0,
|
|
|
|
(locals - parameterFootprint) * BytesPerWord * 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned frame = base + locals;
|
|
|
|
pokeInt(t, frame + FrameNextOffset, t->frame);
|
|
|
|
t->frame = frame;
|
|
|
|
|
|
|
|
t->sp = frame + FrameFootprint;
|
|
|
|
|
|
|
|
pokeInt(t, frame + FrameBaseOffset, base);
|
|
|
|
pokeObject(t, frame + FrameMethodOffset, method);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
popFrame(Thread* t)
|
|
|
|
{
|
|
|
|
t->sp = frameBase(t, t->frame);
|
|
|
|
t->frame = frameNext(t, t->frame);
|
|
|
|
if (t->frame >= 0) {
|
|
|
|
t->code = methodCode(t, frameMethod(t, t->frame));
|
|
|
|
t->ip = frameIp(t, t->frame);
|
|
|
|
} else {
|
|
|
|
t->code = 0;
|
|
|
|
t->ip = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-22 22:47:57 +00:00
|
|
|
void
|
|
|
|
Thread::dispose()
|
|
|
|
{
|
|
|
|
Chain::dispose(vm->system, chain);
|
|
|
|
|
|
|
|
for (Thread* c = child; c; c = c->next) {
|
|
|
|
c->dispose();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-02 00:06:06 +00:00
|
|
|
void
|
2007-06-20 16:58:35 +00:00
|
|
|
visitRoots(Thread* t, Heap::Visitor* v)
|
2007-06-02 00:06:06 +00:00
|
|
|
{
|
2007-06-03 02:00:23 +00:00
|
|
|
t->heapIndex = 0;
|
|
|
|
|
2007-06-13 14:03:08 +00:00
|
|
|
v->visit(&(t->thread));
|
2007-06-02 00:06:06 +00:00
|
|
|
v->visit(&(t->code));
|
|
|
|
v->visit(&(t->exception));
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < t->sp; ++i) {
|
2007-07-04 02:56:02 +00:00
|
|
|
if (t->stack[i * 2] == ObjectTag) {
|
|
|
|
v->visit(reinterpret_cast<object*>(t->stack + (i * 2) + 1));
|
|
|
|
}
|
2007-06-02 00:06:06 +00:00
|
|
|
}
|
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
for (Thread::Protector* p = t->protector; p; p = p->next) {
|
|
|
|
v->visit(p->p);
|
|
|
|
}
|
|
|
|
|
2007-06-21 19:43:33 +00:00
|
|
|
for (Thread* c = t->child; c; c = c->next) {
|
|
|
|
visitRoots(c, v);
|
2007-06-02 00:06:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-22 22:47:57 +00:00
|
|
|
void
|
|
|
|
postCollect(Thread* t)
|
|
|
|
{
|
|
|
|
Chain::dispose(t->vm->system, t->chain);
|
|
|
|
t->chain = 0;
|
|
|
|
|
|
|
|
for (Thread* c = t->child; c; c = c->next) {
|
|
|
|
postCollect(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-02 00:06:06 +00:00
|
|
|
void
|
|
|
|
collect(Machine* m, Heap::CollectionType type)
|
|
|
|
{
|
2007-06-20 16:58:35 +00:00
|
|
|
class Client: public Heap::Client {
|
2007-06-02 00:06:06 +00:00
|
|
|
public:
|
2007-06-20 16:58:35 +00:00
|
|
|
Client(Machine* m): m(m) { }
|
2007-06-02 00:06:06 +00:00
|
|
|
|
2007-06-20 16:58:35 +00:00
|
|
|
virtual void visitRoots(Heap::Visitor* v) {
|
2007-06-14 23:55:06 +00:00
|
|
|
v->visit(&(m->classMap));
|
2007-06-24 19:57:00 +00:00
|
|
|
v->visit(&(m->bootstrapClassMap));
|
2007-06-24 21:49:04 +00:00
|
|
|
v->visit(&(m->builtinMap));
|
2007-07-02 01:42:35 +00:00
|
|
|
v->visit(&(m->monitorMap));
|
2007-06-18 21:13:21 +00:00
|
|
|
v->visit(&(m->types));
|
2007-06-14 23:55:06 +00:00
|
|
|
|
|
|
|
for (Thread* t = m->rootThread; t; t = t->next) {
|
2007-06-20 16:58:35 +00:00
|
|
|
::visitRoots(t, v);
|
|
|
|
}
|
2007-07-02 14:19:05 +00:00
|
|
|
|
|
|
|
Thread* t = m->rootThread;
|
|
|
|
for (object* f = &(m->finalizers); *f;) {
|
|
|
|
object o = finalizerTarget(t, *f);
|
|
|
|
if (m->heap->follow(o) == o) {
|
|
|
|
// object has not been collected
|
|
|
|
object x = *f;
|
|
|
|
*f = finalizerNext(t, x);
|
|
|
|
finalizerNext(t, x) = m->doomed;
|
|
|
|
m->doomed = x;
|
|
|
|
} else {
|
|
|
|
f = &finalizerNext(t, *f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (object* f = &(m->finalizers); *f; f = &finalizerNext(t, *f)) {
|
|
|
|
v->visit(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (object* f = &(m->doomed); *f; f = &finalizerNext(t, *f)) {
|
|
|
|
v->visit(f);
|
|
|
|
}
|
2007-07-04 18:43:42 +00:00
|
|
|
|
|
|
|
for (object p = m->weakReferences; p;) {
|
|
|
|
object o = jreferenceTarget(t, p);
|
|
|
|
object followed = m->heap->follow(o);
|
|
|
|
if (followed == o) {
|
|
|
|
// object has not been collected
|
|
|
|
jreferenceTarget(t, p) = 0;
|
|
|
|
} else {
|
|
|
|
jreferenceTarget(t, p) = followed;
|
|
|
|
}
|
|
|
|
|
|
|
|
object last = p;
|
|
|
|
p = weakReferenceNext(t, p);
|
|
|
|
weakReferenceNext(t, last) = 0;
|
|
|
|
}
|
2007-06-20 16:58:35 +00:00
|
|
|
}
|
|
|
|
|
2007-07-02 01:42:35 +00:00
|
|
|
virtual unsigned sizeInWords(object o) {
|
2007-06-20 17:42:13 +00:00
|
|
|
Thread* t = m->rootThread;
|
|
|
|
|
2007-07-02 01:42:35 +00:00
|
|
|
o = m->heap->follow(mask(o));
|
2007-06-20 16:58:35 +00:00
|
|
|
|
2007-07-02 01:42:35 +00:00
|
|
|
return extendedSize
|
|
|
|
(t, o, baseSize(t, o, m->heap->follow(objectClass(t, o))));
|
|
|
|
}
|
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
virtual unsigned copiedSizeInWords(object o) {
|
2007-07-02 01:42:35 +00:00
|
|
|
Thread* t = m->rootThread;
|
|
|
|
|
|
|
|
o = m->heap->follow(mask(o));
|
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
unsigned n = baseSize(t, o, m->heap->follow(objectClass(t, o)));
|
2007-07-02 01:42:35 +00:00
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
if (objectExtended(t, o) or hashTaken(t, o)) {
|
|
|
|
++ n;
|
|
|
|
}
|
2007-07-02 01:42:35 +00:00
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
return n;
|
|
|
|
}
|
2007-07-02 01:42:35 +00:00
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
virtual void copy(object o, object dst) {
|
|
|
|
Thread* t = m->rootThread;
|
2007-07-02 01:42:35 +00:00
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
o = m->heap->follow(mask(o));
|
2007-07-04 15:56:55 +00:00
|
|
|
object class_ = m->heap->follow(objectClass(t, o));
|
2007-07-02 01:42:35 +00:00
|
|
|
|
2007-07-04 15:56:55 +00:00
|
|
|
unsigned base = baseSize(t, o, class_);
|
2007-07-02 14:19:05 +00:00
|
|
|
unsigned n = extendedSize(t, o, base);
|
2007-07-02 01:42:35 +00:00
|
|
|
|
2007-07-04 17:58:27 +00:00
|
|
|
memcpy(dst, o, n * BytesPerWord);
|
2007-07-02 01:42:35 +00:00
|
|
|
|
|
|
|
if (hashTaken(t, o)) {
|
|
|
|
extendedWord(t, dst, base) = takeHash(t, o);
|
|
|
|
cast<uintptr_t>(dst, 0) &= PointerMask;
|
|
|
|
cast<uintptr_t>(dst, 0) |= ExtendedMark;
|
|
|
|
}
|
2007-07-04 15:56:55 +00:00
|
|
|
|
|
|
|
if (classVmFlags(t, class_) & WeakReferenceFlag) {
|
|
|
|
weakReferenceNext(t, dst) = m->weakReferences;
|
|
|
|
m->weakReferences = dst;
|
|
|
|
}
|
2007-06-20 16:58:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void walk(void* p, Heap::Walker* w) {
|
2007-06-20 17:42:13 +00:00
|
|
|
Thread* t = m->rootThread;
|
|
|
|
|
2007-07-01 21:34:22 +00:00
|
|
|
p = m->heap->follow(mask(p));
|
|
|
|
object class_ = m->heap->follow(objectClass(t, p));
|
2007-06-20 16:58:35 +00:00
|
|
|
object objectMask = m->heap->follow(classObjectMask(t, class_));
|
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
if (objectMask) {
|
2007-06-21 22:50:52 +00:00
|
|
|
// fprintf(stderr, "p: %p; class: %p; mask: %p; mask length: %d\n",
|
|
|
|
// p, class_, objectMask, intArrayLength(t, objectMask));
|
2007-06-21 18:35:24 +00:00
|
|
|
|
2007-07-04 15:56:55 +00:00
|
|
|
unsigned vmFlags = classVmFlags(t, class_);
|
2007-06-21 18:35:24 +00:00
|
|
|
unsigned fixedSize = classFixedSize(t, class_);
|
|
|
|
unsigned arrayElementSize = classArrayElementSize(t, class_);
|
|
|
|
unsigned arrayLength
|
|
|
|
= (arrayElementSize ? cast<uint32_t>(p, fixedSize - 4) : 0);
|
|
|
|
|
|
|
|
int mask[intArrayLength(t, objectMask)];
|
|
|
|
memcpy(mask, &intArrayBody(t, objectMask, 0),
|
|
|
|
intArrayLength(t, objectMask) * 4);
|
|
|
|
|
|
|
|
// fprintf
|
|
|
|
// (stderr,
|
|
|
|
// "fixed size: %d; array length: %d; element size: %d; mask: %x\n",
|
|
|
|
// fixedSize, arrayLength, arrayElementSize, mask[0]);
|
|
|
|
|
|
|
|
unsigned fixedSizeInWords = divide(fixedSize, BytesPerWord);
|
|
|
|
unsigned arrayElementSizeInWords
|
|
|
|
= divide(arrayElementSize, BytesPerWord);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < fixedSizeInWords; ++i) {
|
2007-07-04 15:56:55 +00:00
|
|
|
if ((i != 1 or (vmFlags & WeakReferenceFlag) == 0)
|
|
|
|
and mask[wordOf(i)] & (static_cast<uintptr_t>(1) << bitOf(i)))
|
|
|
|
{
|
2007-06-21 18:35:24 +00:00
|
|
|
if (not w->visit(i)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2007-06-20 16:58:35 +00:00
|
|
|
}
|
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
bool arrayObjectElements = false;
|
|
|
|
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
|
|
|
|
unsigned k = fixedSizeInWords + j;
|
2007-06-20 16:58:35 +00:00
|
|
|
if (mask[wordOf(k)] & (static_cast<uintptr_t>(1) << bitOf(k))) {
|
2007-06-21 18:35:24 +00:00
|
|
|
arrayObjectElements = true;
|
|
|
|
break;
|
2007-06-20 16:58:35 +00:00
|
|
|
}
|
|
|
|
}
|
2007-06-21 18:35:24 +00:00
|
|
|
|
|
|
|
if (arrayObjectElements) {
|
|
|
|
for (unsigned i = 0; i < arrayLength; ++i) {
|
|
|
|
for (unsigned j = 0; j < arrayElementSizeInWords; ++j) {
|
|
|
|
unsigned k = fixedSizeInWords + j;
|
|
|
|
if (mask[wordOf(k)] & (static_cast<uintptr_t>(1) << bitOf(k))) {
|
|
|
|
if (not w->visit
|
|
|
|
(fixedSizeInWords + (i * arrayElementSizeInWords) + j))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
w->visit(0);
|
2007-06-02 00:06:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2007-06-14 23:55:06 +00:00
|
|
|
Machine* m;
|
2007-06-02 00:06:06 +00:00
|
|
|
} it(m);
|
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
m->unsafe = true;
|
2007-06-03 02:00:23 +00:00
|
|
|
m->heap->collect(type, &it);
|
2007-06-21 18:35:24 +00:00
|
|
|
m->unsafe = false;
|
2007-06-22 22:47:57 +00:00
|
|
|
|
|
|
|
postCollect(m->rootThread);
|
2007-07-02 14:19:05 +00:00
|
|
|
|
|
|
|
Thread* t = m->rootThread;
|
|
|
|
for (object f = m->doomed; f; f = tripleThird(t, f)) {
|
|
|
|
reinterpret_cast<void (*)(Thread*, object)>(finalizerFinalize(t, f))
|
|
|
|
(t, finalizerTarget(t, f));
|
|
|
|
}
|
|
|
|
m->doomed = 0;
|
2007-07-04 15:56:55 +00:00
|
|
|
|
|
|
|
m->weakReferences = 0;
|
2007-06-02 00:06:06 +00:00
|
|
|
}
|
|
|
|
|
2007-06-03 02:00:23 +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
|
|
|
|
2007-06-15 00:50:55 +00:00
|
|
|
ACQUIRE_RAW(t, t->vm->stateLock);
|
2007-06-02 00:06:06 +00:00
|
|
|
|
2007-06-03 02:00:23 +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) {
|
2007-06-03 02:00:23 +00:00
|
|
|
// 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-03 02:00:23 +00:00
|
|
|
|
2007-06-02 00:06:06 +00:00
|
|
|
while (t->vm->activeCount > 1) {
|
2007-07-01 21:34:22 +00:00
|
|
|
t->vm->stateLock->wait(t, 0);
|
2007-06-02 00:06:06 +00:00
|
|
|
}
|
2007-06-03 02:00:23 +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: {
|
2007-06-03 02:00:23 +00:00
|
|
|
assert(t, t->vm->exclusive == t);
|
|
|
|
t->vm->exclusive = 0;
|
|
|
|
} break;
|
|
|
|
|
2007-06-05 00:28:52 +00:00
|
|
|
case Thread::ActiveState: break;
|
2007-06-03 02:00:23 +00:00
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
-- t->vm->activeCount;
|
2007-06-05 00:28:52 +00:00
|
|
|
if (s == Thread::ZombieState) {
|
2007-06-03 02:00:23 +00:00
|
|
|
-- t->vm->liveCount;
|
|
|
|
}
|
|
|
|
t->state = s;
|
2007-06-02 00:06:06 +00:00
|
|
|
|
2007-06-15 00:50:55 +00:00
|
|
|
t->vm->stateLock->notifyAll(t);
|
2007-06-03 02:00:23 +00:00
|
|
|
} break;
|
|
|
|
|
2007-06-05 00:28:52 +00:00
|
|
|
case Thread::ActiveState: {
|
|
|
|
switch (t->state) {
|
|
|
|
case Thread::ExclusiveState: {
|
2007-06-03 02:00:23 +00:00
|
|
|
assert(t, t->vm->exclusive == t);
|
|
|
|
|
|
|
|
t->state = s;
|
|
|
|
t->vm->exclusive = 0;
|
|
|
|
|
2007-06-15 00:50:55 +00:00
|
|
|
t->vm->stateLock->notifyAll(t);
|
2007-06-03 02:00:23 +00:00
|
|
|
} break;
|
|
|
|
|
2007-06-05 00:28:52 +00:00
|
|
|
case Thread::NoState:
|
|
|
|
case Thread::IdleState: {
|
2007-06-03 02:00:23 +00:00
|
|
|
while (t->vm->exclusive) {
|
2007-07-01 21:34:22 +00:00
|
|
|
t->vm->stateLock->wait(t, 0);
|
2007-06-03 02:00:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
++ t->vm->activeCount;
|
2007-06-05 00:28:52 +00:00
|
|
|
if (t->state == Thread::NoState) {
|
2007-06-03 02:00:23 +00:00
|
|
|
++ 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: {
|
2007-06-03 02:00:23 +00:00
|
|
|
assert(t, t->vm->exclusive == t);
|
|
|
|
t->vm->exclusive = 0;
|
|
|
|
} break;
|
|
|
|
|
2007-06-05 00:28:52 +00:00
|
|
|
case Thread::ActiveState: break;
|
2007-06-03 02:00:23 +00:00
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
-- t->vm->activeCount;
|
|
|
|
t->state = s;
|
|
|
|
|
|
|
|
while (t->vm->liveCount > 1) {
|
2007-07-01 21:34:22 +00:00
|
|
|
t->vm->stateLock->wait(t, 0);
|
2007-06-03 02:00:23 +00:00
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default: abort(t);
|
2007-06-02 00:06:06 +00:00
|
|
|
}
|
2007-06-03 02:00:23 +00:00
|
|
|
}
|
2007-06-02 00:06:06 +00:00
|
|
|
|
2007-06-22 22:47:57 +00:00
|
|
|
inline object
|
|
|
|
allocateLarge(Thread* t, unsigned sizeInBytes)
|
2007-06-03 02:00:23 +00:00
|
|
|
{
|
2007-06-22 22:47:57 +00:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
if (sizeInBytes > Thread::HeapSizeInBytes and t->chain == 0) {
|
|
|
|
return allocateLarge(t, sizeInBytes);
|
2007-06-03 02:00:23 +00:00
|
|
|
}
|
|
|
|
|
2007-06-15 00:50:55 +00:00
|
|
|
ACQUIRE_RAW(t, t->vm->stateLock);
|
2007-06-03 02:00:23 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-06-22 20:55:11 +00:00
|
|
|
if (t->heapIndex + divide(sizeInBytes, BytesPerWord)
|
2007-06-22 21:31:45 +00:00
|
|
|
>= Thread::HeapSizeInWords)
|
2007-06-22 20:55:11 +00:00
|
|
|
{
|
2007-06-03 02:00:23 +00:00
|
|
|
enter(t, Thread::ExclusiveState);
|
|
|
|
collect(t->vm, Heap::MinorCollection);
|
|
|
|
enter(t, Thread::ActiveState);
|
|
|
|
}
|
2007-06-22 22:47:57 +00:00
|
|
|
|
|
|
|
if (sizeInBytes > Thread::HeapSizeInBytes) {
|
|
|
|
return allocateLarge(t, sizeInBytes);
|
|
|
|
} else {
|
|
|
|
return allocateSmall(t, sizeInBytes);
|
|
|
|
}
|
2007-06-02 00:06:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
2007-06-22 20:55:11 +00:00
|
|
|
allocate(Thread* t, unsigned sizeInBytes)
|
2007-06-02 00:06:06 +00:00
|
|
|
{
|
2007-06-22 20:55:11 +00:00
|
|
|
if (UNLIKELY(t->heapIndex + divide(sizeInBytes, BytesPerWord)
|
2007-06-22 21:31:45 +00:00
|
|
|
>= Thread::HeapSizeInWords
|
2007-06-02 00:06:06 +00:00
|
|
|
or t->vm->exclusive))
|
|
|
|
{
|
2007-06-22 22:47:57 +00:00
|
|
|
return allocate2(t, sizeInBytes);
|
|
|
|
} else {
|
|
|
|
return allocateSmall(t, sizeInBytes);
|
2007-06-02 00:06:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-08 14:23:04 +00:00
|
|
|
inline void
|
|
|
|
set(Thread* t, object& target, object value)
|
|
|
|
{
|
|
|
|
target = value;
|
2007-06-15 16:00:08 +00:00
|
|
|
if (t->vm->heap->needsMark(&target)) {
|
|
|
|
ACQUIRE_RAW(t, t->vm->heapLock);
|
|
|
|
t->vm->heap->mark(&target);
|
2007-06-15 00:50:55 +00:00
|
|
|
}
|
2007-06-08 14:23:04 +00:00
|
|
|
}
|
|
|
|
|
2007-06-07 00:30:16 +00:00
|
|
|
inline object
|
|
|
|
make(Thread* t, object class_)
|
|
|
|
{
|
2007-06-08 14:23:04 +00:00
|
|
|
PROTECT(t, class_);
|
2007-06-25 02:20:35 +00:00
|
|
|
unsigned sizeInBytes = pad(classFixedSize(t, class_));
|
2007-06-22 20:55:11 +00:00
|
|
|
object instance = allocate(t, sizeInBytes);
|
2007-06-07 00:30:16 +00:00
|
|
|
*static_cast<object*>(instance) = class_;
|
|
|
|
memset(static_cast<object*>(instance) + sizeof(object), 0,
|
2007-06-22 20:55:11 +00:00
|
|
|
sizeInBytes - sizeof(object));
|
2007-06-07 00:30:16 +00:00
|
|
|
return instance;
|
|
|
|
}
|
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
void
|
|
|
|
addFinalizer(Thread* t, object target, void (*finalize)(Thread*, object))
|
2007-06-25 01:34:07 +00:00
|
|
|
{
|
2007-07-02 14:19:05 +00:00
|
|
|
PROTECT(t, target);
|
2007-06-25 01:34:07 +00:00
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
ACQUIRE(t, t->vm->finalizerLock);
|
2007-07-02 04:03:44 +00:00
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
object p = makePointer(t, reinterpret_cast<void*>(finalize));
|
|
|
|
t->vm->finalizers = makeTriple(t, target, p, t->vm->finalizers);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
removeMonitor(Thread* t, object o)
|
|
|
|
{
|
2007-07-04 15:56:55 +00:00
|
|
|
hashMapRemove(t, t->vm->monitorMap, o, objectHash, referenceEqual);
|
2007-07-02 14:19:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System::Monitor*
|
|
|
|
objectMonitor(Thread* t, object o)
|
|
|
|
{
|
2007-07-04 15:56:55 +00:00
|
|
|
object p = hashMapFind(t, t->vm->monitorMap, o, objectHash, referenceEqual);
|
2007-07-02 01:42:35 +00:00
|
|
|
|
2007-07-02 04:03:44 +00:00
|
|
|
if (p) {
|
|
|
|
return static_cast<System::Monitor*>(pointerValue(t, p));
|
|
|
|
} else {
|
2007-07-02 14:19:05 +00:00
|
|
|
PROTECT(t, o);
|
|
|
|
|
|
|
|
ENTER(t, Thread::ExclusiveState);
|
|
|
|
|
|
|
|
System::Monitor* m;
|
2007-07-02 01:42:35 +00:00
|
|
|
System::Status s = t->vm->system->make(&m);
|
|
|
|
expect(t, t->vm->system->success(s));
|
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
p = makePointer(t, m);
|
2007-07-04 15:56:55 +00:00
|
|
|
PROTECT(t, p);
|
|
|
|
|
|
|
|
object wr = makeWeakReference(t, o, 0);
|
|
|
|
|
|
|
|
hashMapInsert(t, t->vm->monitorMap, wr, p, referenceHash);
|
2007-07-02 04:03:44 +00:00
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
addFinalizer(t, o, removeMonitor);
|
2007-07-02 01:42:35 +00:00
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
return m;
|
2007-07-02 01:42:35 +00:00
|
|
|
}
|
2007-06-25 01:34:07 +00:00
|
|
|
}
|
|
|
|
|
2007-06-07 00:30:16 +00:00
|
|
|
object
|
2007-06-18 21:13:21 +00:00
|
|
|
makeByteArray(Thread* t, const char* format, va_list a)
|
2007-06-07 00:30:16 +00:00
|
|
|
{
|
|
|
|
static const unsigned Size = 256;
|
|
|
|
char buffer[Size];
|
|
|
|
|
2007-06-18 21:13:21 +00:00
|
|
|
vsnprintf(buffer, Size - 1, format, a);
|
|
|
|
|
2007-06-21 19:43:33 +00:00
|
|
|
object s = makeByteArray(t, strlen(buffer) + 1, false);
|
2007-06-18 21:13:21 +00:00
|
|
|
memcpy(&byteArrayBody(t, s, 0), buffer, byteArrayLength(t, s));
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeByteArray(Thread* t, const char* format, ...)
|
|
|
|
{
|
2007-06-07 00:30:16 +00:00
|
|
|
va_list a;
|
|
|
|
va_start(a, format);
|
2007-06-18 21:13:21 +00:00
|
|
|
object s = makeByteArray(t, format, a);
|
2007-06-07 00:30:16 +00:00
|
|
|
va_end(a);
|
|
|
|
|
2007-06-18 21:13:21 +00:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeString(Thread* t, const char* format, ...)
|
|
|
|
{
|
|
|
|
va_list a;
|
|
|
|
va_start(a, format);
|
|
|
|
object s = makeByteArray(t, format, a);
|
|
|
|
va_end(a);
|
2007-06-08 00:23:12 +00:00
|
|
|
|
|
|
|
return makeString(t, s, 0, byteArrayLength(t, s), 0);
|
|
|
|
}
|
2007-06-07 00:30:16 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
object
|
2007-07-06 01:06:06 +00:00
|
|
|
makeTrace(Thread* t, int frame)
|
2007-06-08 00:23:12 +00:00
|
|
|
{
|
2007-06-30 01:37:45 +00:00
|
|
|
unsigned count = 0;
|
2007-07-06 01:06:06 +00:00
|
|
|
for (int f = frame; f >= 0; f = frameNext(t, f)) {
|
2007-06-30 01:37:45 +00:00
|
|
|
++ count;
|
2007-06-08 00:23:12 +00:00
|
|
|
}
|
2007-06-30 01:37:45 +00:00
|
|
|
|
|
|
|
object trace = makeObjectArray
|
|
|
|
(t, arrayBody(t, t->vm->types, Machine::StackTraceElementType),
|
|
|
|
count, true);
|
|
|
|
PROTECT(t, trace);
|
|
|
|
|
|
|
|
unsigned index = 0;
|
2007-07-06 01:06:06 +00:00
|
|
|
for (int f = frame; f >= 0; f = frameNext(t, f)) {
|
2007-06-30 01:37:45 +00:00
|
|
|
object e = makeStackTraceElement(t, frameMethod(t, f), frameIp(t, f));
|
|
|
|
set(t, objectArrayBody(t, trace, index++), e);
|
|
|
|
}
|
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
return trace;
|
|
|
|
}
|
|
|
|
|
2007-06-30 01:37:45 +00:00
|
|
|
object
|
|
|
|
makeTrace(Thread* t)
|
|
|
|
{
|
2007-07-06 01:06:06 +00:00
|
|
|
pokeInt(t, t->frame + FrameIpOffset, t->ip);
|
2007-06-30 01:37:45 +00:00
|
|
|
return makeTrace(t, t->frame);
|
|
|
|
}
|
|
|
|
|
2007-06-25 01:34:07 +00:00
|
|
|
object
|
|
|
|
makeRuntimeException(Thread* t, object message)
|
|
|
|
{
|
|
|
|
PROTECT(t, message);
|
|
|
|
object trace = makeTrace(t);
|
2007-06-29 02:58:48 +00:00
|
|
|
return makeRuntimeException(t, message, trace, 0);
|
2007-06-25 01:34:07 +00:00
|
|
|
}
|
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
object
|
|
|
|
makeArrayIndexOutOfBoundsException(Thread* t, object message)
|
|
|
|
{
|
|
|
|
PROTECT(t, message);
|
|
|
|
object trace = makeTrace(t);
|
2007-06-24 19:57:00 +00:00
|
|
|
return makeArrayIndexOutOfBoundsException(t, message, trace, 0);
|
2007-06-08 00:23:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeNegativeArrayStoreException(Thread* t, object message)
|
|
|
|
{
|
|
|
|
PROTECT(t, message);
|
|
|
|
object trace = makeTrace(t);
|
2007-06-24 19:57:00 +00:00
|
|
|
return makeNegativeArrayStoreException(t, message, trace, 0);
|
2007-06-08 00:23:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeClassCastException(Thread* t, object message)
|
|
|
|
{
|
|
|
|
PROTECT(t, message);
|
|
|
|
object trace = makeTrace(t);
|
2007-06-24 19:57:00 +00:00
|
|
|
return makeClassCastException(t, message, trace, 0);
|
2007-06-14 23:55:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeClassNotFoundException(Thread* t, object message)
|
|
|
|
{
|
|
|
|
PROTECT(t, message);
|
|
|
|
object trace = makeTrace(t);
|
2007-06-24 19:57:00 +00:00
|
|
|
return makeClassNotFoundException(t, message, trace, 0);
|
2007-06-08 00:23:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeNullPointerException(Thread* t)
|
|
|
|
{
|
2007-06-24 19:57:00 +00:00
|
|
|
return makeNullPointerException(t, 0, makeTrace(t), 0);
|
2007-06-08 00:23:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeStackOverflowError(Thread* t)
|
|
|
|
{
|
2007-06-24 19:57:00 +00:00
|
|
|
return makeStackOverflowError(t, 0, makeTrace(t), 0);
|
2007-06-07 00:30:16 +00:00
|
|
|
}
|
|
|
|
|
2007-06-14 02:41:59 +00:00
|
|
|
object
|
|
|
|
makeNoSuchFieldError(Thread* t, object message)
|
|
|
|
{
|
|
|
|
PROTECT(t, message);
|
|
|
|
object trace = makeTrace(t);
|
2007-06-24 19:57:00 +00:00
|
|
|
return makeNoSuchFieldError(t, message, trace, 0);
|
2007-06-14 02:41:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeNoSuchMethodError(Thread* t, object message)
|
|
|
|
{
|
|
|
|
PROTECT(t, message);
|
|
|
|
object trace = makeTrace(t);
|
2007-06-24 19:57:00 +00:00
|
|
|
return makeNoSuchMethodError(t, message, trace, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
object
|
|
|
|
makeUnsatisfiedLinkError(Thread* t, object message)
|
|
|
|
{
|
|
|
|
PROTECT(t, message);
|
|
|
|
object trace = makeTrace(t);
|
|
|
|
return makeUnsatisfiedLinkError(t, message, trace, 0);
|
2007-06-14 02:41:59 +00:00
|
|
|
}
|
|
|
|
|
2007-06-24 01:39:49 +00:00
|
|
|
unsigned
|
2007-06-24 19:57:00 +00:00
|
|
|
fieldCode(Thread* t, unsigned javaCode)
|
2007-06-11 23:40:24 +00:00
|
|
|
{
|
2007-06-24 01:39:49 +00:00
|
|
|
switch (javaCode) {
|
2007-06-16 21:39:05 +00:00
|
|
|
case 'B':
|
2007-06-24 01:39:49 +00:00
|
|
|
return ByteField;
|
2007-06-16 21:39:05 +00:00
|
|
|
case 'C':
|
2007-06-24 01:39:49 +00:00
|
|
|
return CharField;
|
2007-06-16 21:39:05 +00:00
|
|
|
case 'D':
|
2007-06-24 01:39:49 +00:00
|
|
|
return DoubleField;
|
2007-06-16 21:39:05 +00:00
|
|
|
case 'F':
|
2007-06-24 01:39:49 +00:00
|
|
|
return FloatField;
|
2007-06-16 21:39:05 +00:00
|
|
|
case 'I':
|
2007-06-24 01:39:49 +00:00
|
|
|
return IntField;
|
2007-06-16 21:39:05 +00:00
|
|
|
case 'J':
|
2007-06-24 01:39:49 +00:00
|
|
|
return LongField;
|
2007-06-16 21:39:05 +00:00
|
|
|
case 'S':
|
2007-06-24 01:39:49 +00:00
|
|
|
return ShortField;
|
2007-06-25 02:20:35 +00:00
|
|
|
case 'V':
|
|
|
|
return VoidField;
|
2007-06-16 21:39:05 +00:00
|
|
|
case 'Z':
|
2007-06-24 01:39:49 +00:00
|
|
|
return BooleanField;
|
2007-06-16 21:39:05 +00:00
|
|
|
case 'L':
|
|
|
|
case '[':
|
2007-06-24 01:39:49 +00:00
|
|
|
return ObjectField;
|
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-29 02:58:48 +00:00
|
|
|
unsigned
|
|
|
|
fieldType(Thread* t, unsigned code)
|
|
|
|
{
|
|
|
|
switch (code) {
|
|
|
|
case VoidField:
|
|
|
|
return VOID_TYPE;
|
|
|
|
case ByteField:
|
|
|
|
case BooleanField:
|
|
|
|
return INT8_TYPE;
|
|
|
|
case CharField:
|
|
|
|
case ShortField:
|
|
|
|
return INT16_TYPE;
|
|
|
|
case DoubleField:
|
|
|
|
return DOUBLE_TYPE;
|
|
|
|
case FloatField:
|
|
|
|
return FLOAT_TYPE;
|
|
|
|
case IntField:
|
|
|
|
return INT32_TYPE;
|
|
|
|
case LongField:
|
|
|
|
return INT64_TYPE;
|
|
|
|
case ObjectField:
|
|
|
|
return POINTER_TYPE;
|
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-24 01:39:49 +00:00
|
|
|
unsigned
|
2007-06-24 19:57:00 +00:00
|
|
|
primitiveSize(Thread* t, unsigned code)
|
2007-06-24 01:39:49 +00:00
|
|
|
{
|
|
|
|
switch (code) {
|
2007-06-25 02:20:35 +00:00
|
|
|
case VoidField:
|
|
|
|
return 0;
|
2007-06-24 01:39:49 +00:00
|
|
|
case ByteField:
|
|
|
|
case BooleanField:
|
|
|
|
return 1;
|
|
|
|
case CharField:
|
|
|
|
case ShortField:
|
|
|
|
return 2;
|
|
|
|
case FloatField:
|
|
|
|
case IntField:
|
|
|
|
return 4;
|
2007-06-25 02:20:35 +00:00
|
|
|
case DoubleField:
|
|
|
|
case LongField:
|
|
|
|
return 8;
|
2007-06-24 01:39:49 +00:00
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-11 23:40:24 +00:00
|
|
|
inline void
|
|
|
|
setStatic(Thread* t, object field, object value)
|
|
|
|
{
|
2007-06-18 21:13:21 +00:00
|
|
|
set(t, arrayBody(t, classStaticTable(t, fieldClass(t, field)),
|
|
|
|
fieldOffset(t, field)), value);
|
2007-06-11 23:40:24 +00:00
|
|
|
}
|
|
|
|
|
2007-06-09 02:29:56 +00:00
|
|
|
bool
|
|
|
|
instanceOf(Thread* t, object class_, object o)
|
|
|
|
{
|
|
|
|
if (o == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-07-05 02:25:25 +00:00
|
|
|
if (classFlags(t, class_) & ACC_INTERFACE) {
|
2007-07-01 21:34:22 +00:00
|
|
|
for (object oc = objectClass(t, o); oc; oc = classSuper(t, oc)) {
|
2007-06-09 02:29:56 +00:00
|
|
|
object itable = classInterfaceTable(t, oc);
|
2007-06-17 22:03:27 +00:00
|
|
|
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
2007-06-18 21:13:21 +00:00
|
|
|
if (arrayBody(t, itable, i) == class_) {
|
2007-06-09 02:29:56 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2007-07-01 21:34:22 +00:00
|
|
|
for (object oc = objectClass(t, o); oc; oc = classSuper(t, oc)) {
|
2007-06-17 22:03:27 +00:00
|
|
|
if (oc == class_) {
|
2007-06-09 02:29:56 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-06-11 23:40:24 +00:00
|
|
|
object
|
|
|
|
findInterfaceMethod(Thread* t, object method, object o)
|
|
|
|
{
|
2007-06-17 22:03:27 +00:00
|
|
|
object interface = methodClass(t, method);
|
2007-07-01 21:34:22 +00:00
|
|
|
object itable = classInterfaceTable(t, objectClass(t, o));
|
2007-06-17 22:03:27 +00:00
|
|
|
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
2007-06-18 21:13:21 +00:00
|
|
|
if (arrayBody(t, itable, i) == interface) {
|
|
|
|
return arrayBody(t, arrayBody(t, itable, i + 1),
|
|
|
|
methodOffset(t, method));
|
2007-06-11 23:40:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
abort(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
2007-06-13 14:03:08 +00:00
|
|
|
findMethod(Thread* t, object method, object class_)
|
2007-06-11 23:40:24 +00:00
|
|
|
{
|
2007-06-18 21:13:21 +00:00
|
|
|
return arrayBody(t, classVirtualTable(t, class_),
|
|
|
|
methodOffset(t, method));
|
2007-06-11 23:40:24 +00:00
|
|
|
}
|
|
|
|
|
2007-06-13 14:03:08 +00:00
|
|
|
inline object
|
|
|
|
findVirtualMethod(Thread* t, object method, object o)
|
|
|
|
{
|
2007-07-01 21:34:22 +00:00
|
|
|
return findMethod(t, method, objectClass(t, o));
|
2007-06-13 14:03:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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_) {
|
2007-06-13 14:03:08 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-06-14 02:41:59 +00:00
|
|
|
inline int
|
|
|
|
strcmp(const int8_t* a, const int8_t* b)
|
|
|
|
{
|
|
|
|
return ::strcmp(reinterpret_cast<const char*>(a),
|
|
|
|
reinterpret_cast<const char*>(b));
|
|
|
|
}
|
|
|
|
|
2007-06-13 14:03:08 +00:00
|
|
|
inline bool
|
|
|
|
isSpecialMethod(Thread* t, object method, object class_)
|
|
|
|
{
|
|
|
|
return (classFlags(t, class_) & ACC_SUPER)
|
2007-06-14 02:41:59 +00:00
|
|
|
and strcmp(reinterpret_cast<const int8_t*>("<init>"),
|
2007-06-18 21:13:21 +00:00
|
|
|
&byteArrayBody(t, methodName(t, method), 0)) != 0
|
2007-06-13 14:03:08 +00:00
|
|
|
and isSuperclass(t, methodClass(t, method), class_);
|
|
|
|
}
|
|
|
|
|
2007-06-14 02:12:28 +00:00
|
|
|
object
|
2007-06-14 23:55:06 +00:00
|
|
|
find(Thread* t, object class_, object table, object reference,
|
2007-06-14 02:41:59 +00:00
|
|
|
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) {
|
2007-06-21 01:38:02 +00:00
|
|
|
object o = arrayBody(t, table, i);
|
|
|
|
|
|
|
|
if (strcmp(&byteArrayBody(t, name(t, o), 0),
|
2007-06-18 21:13:21 +00:00
|
|
|
&byteArrayBody(t, n, 0)) == 0 and
|
2007-06-21 01:38:02 +00:00
|
|
|
strcmp(&byteArrayBody(t, spec(t, o), 0),
|
2007-06-18 21:13:21 +00:00
|
|
|
&byteArrayBody(t, s, 0)) == 0)
|
2007-06-14 02:12:28 +00:00
|
|
|
{
|
2007-06-21 01:38:02 +00:00
|
|
|
return o;
|
2007-06-14 02:12:28 +00:00
|
|
|
}
|
|
|
|
}
|
2007-06-14 02:41:59 +00:00
|
|
|
|
|
|
|
object message = makeString
|
2007-06-21 01:38:02 +00:00
|
|
|
(t, "%s:%s not found in %s",
|
2007-06-18 21:13:21 +00:00
|
|
|
&byteArrayBody(t, n, 0),
|
|
|
|
&byteArrayBody(t, s, 0),
|
|
|
|
&byteArrayBody(t, className(t, class_), 0));
|
2007-06-14 02:41:59 +00:00
|
|
|
t->exception = makeError(t, message);
|
2007-06-14 02:12:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-14 02:41:59 +00:00
|
|
|
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);
|
2007-06-14 02:41:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object
|
|
|
|
parsePool(Thread* t, Stream& s)
|
|
|
|
{
|
|
|
|
unsigned poolCount = s.read2() - 1;
|
2007-06-21 19:43:33 +00:00
|
|
|
object pool = makeArray(t, poolCount, true);
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
PROTECT(t, pool);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < poolCount; ++i) {
|
|
|
|
unsigned c = s.read1();
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case CONSTANT_Integer: {
|
|
|
|
object value = makeInt(t, s.read4());
|
|
|
|
set(t, arrayBody(t, pool, i), value);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_Float: {
|
|
|
|
object value = makeFloat(t, s.readFloat());
|
|
|
|
set(t, arrayBody(t, pool, i), value);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_Long: {
|
|
|
|
object value = makeLong(t, s.read8());
|
|
|
|
set(t, arrayBody(t, pool, i), value);
|
2007-07-04 22:27:08 +00:00
|
|
|
++i;
|
2007-06-21 01:38:02 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_Double: {
|
|
|
|
object value = makeLong(t, s.readDouble());
|
|
|
|
set(t, arrayBody(t, pool, i), value);
|
2007-07-04 22:27:08 +00:00
|
|
|
++i;
|
2007-06-21 01:38:02 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_Utf8: {
|
|
|
|
unsigned length = s.read2();
|
2007-06-21 19:43:33 +00:00
|
|
|
object value = makeByteArray(t, length + 1, false);
|
2007-06-21 01:38:02 +00:00
|
|
|
s.read(reinterpret_cast<uint8_t*>(&byteArrayBody(t, value, 0)), length);
|
|
|
|
byteArrayBody(t, value, length) = 0;
|
|
|
|
set(t, arrayBody(t, pool, i), value);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_Class: {
|
2007-06-21 19:43:33 +00:00
|
|
|
object value = makeIntArray(t, 2, false);
|
2007-06-21 01:38:02 +00:00
|
|
|
intArrayBody(t, value, 0) = c;
|
|
|
|
intArrayBody(t, value, 1) = s.read2();
|
|
|
|
set(t, arrayBody(t, pool, i), value);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_String: {
|
2007-06-21 19:43:33 +00:00
|
|
|
object value = makeIntArray(t, 2, false);
|
2007-06-21 01:38:02 +00:00
|
|
|
intArrayBody(t, value, 0) = c;
|
|
|
|
intArrayBody(t, value, 1) = s.read2();
|
|
|
|
set(t, arrayBody(t, pool, i), value);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_NameAndType: {
|
2007-06-21 19:43:33 +00:00
|
|
|
object value = makeIntArray(t, 3, false);
|
2007-06-21 01:38:02 +00:00
|
|
|
intArrayBody(t, value, 0) = c;
|
|
|
|
intArrayBody(t, value, 1) = s.read2();
|
|
|
|
intArrayBody(t, value, 2) = s.read2();
|
|
|
|
set(t, arrayBody(t, pool, i), value);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_Fieldref:
|
|
|
|
case CONSTANT_Methodref:
|
|
|
|
case CONSTANT_InterfaceMethodref: {
|
2007-06-21 19:43:33 +00:00
|
|
|
object value = makeIntArray(t, 3, false);
|
2007-06-21 01:38:02 +00:00
|
|
|
intArrayBody(t, value, 0) = c;
|
|
|
|
intArrayBody(t, value, 1) = s.read2();
|
|
|
|
intArrayBody(t, value, 2) = s.read2();
|
|
|
|
set(t, arrayBody(t, pool, i), value);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < poolCount; ++i) {
|
|
|
|
object o = arrayBody(t, pool, i);
|
2007-07-04 22:27:08 +00:00
|
|
|
if (o and objectClass(t, o)
|
|
|
|
== arrayBody(t, t->vm->types, Machine::IntArrayType))
|
2007-07-01 21:34:22 +00:00
|
|
|
{
|
2007-06-21 01:38:02 +00:00
|
|
|
switch (intArrayBody(t, o, 0)) {
|
|
|
|
case CONSTANT_Class: {
|
|
|
|
set(t, arrayBody(t, pool, i),
|
|
|
|
arrayBody(t, pool, intArrayBody(t, o, 1) - 1));
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_String: {
|
|
|
|
object bytes = arrayBody(t, pool, intArrayBody(t, o, 1) - 1);
|
|
|
|
object value = makeString(t, bytes, 0, byteArrayLength(t, bytes), 0);
|
|
|
|
set(t, arrayBody(t, pool, i), value);
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case CONSTANT_NameAndType: {
|
|
|
|
object name = arrayBody(t, pool, intArrayBody(t, o, 1) - 1);
|
|
|
|
object type = arrayBody(t, pool, intArrayBody(t, o, 2) - 1);
|
|
|
|
object value = makePair(t, name, type);
|
|
|
|
set(t, arrayBody(t, pool, i), value);
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < poolCount; ++i) {
|
|
|
|
object o = arrayBody(t, pool, i);
|
2007-07-04 22:27:08 +00:00
|
|
|
if (o and objectClass(t, o)
|
|
|
|
== arrayBody(t, t->vm->types, Machine::IntArrayType))
|
2007-07-01 21:34:22 +00:00
|
|
|
{
|
2007-06-21 01:38:02 +00:00
|
|
|
switch (intArrayBody(t, o, 0)) {
|
|
|
|
case CONSTANT_Fieldref:
|
|
|
|
case CONSTANT_Methodref:
|
|
|
|
case CONSTANT_InterfaceMethodref: {
|
|
|
|
object c = arrayBody(t, pool, intArrayBody(t, o, 1) - 1);
|
|
|
|
object nameAndType = arrayBody(t, pool, intArrayBody(t, o, 2) - 1);
|
|
|
|
object value = makeReference
|
|
|
|
(t, c, pairFirst(t, nameAndType), pairSecond(t, nameAndType));
|
|
|
|
set(t, arrayBody(t, pool, i), value);
|
|
|
|
} break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
|
2007-07-05 02:25:25 +00:00
|
|
|
void
|
|
|
|
addInterfaces(Thread* t, object class_, object map)
|
|
|
|
{
|
|
|
|
object table = classInterfaceTable(t, class_);
|
|
|
|
if (table) {
|
|
|
|
unsigned increment = 2;
|
|
|
|
if (classFlags(t, class_) & ACC_INTERFACE) {
|
|
|
|
increment = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PROTECT(t, map);
|
|
|
|
PROTECT(t, table);
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, table); i += increment) {
|
|
|
|
object interface = arrayBody(t, table, i);
|
|
|
|
object name = className(t, interface);
|
|
|
|
hashMapInsertOrReplace(t, map, name, interface, byteArrayHash,
|
|
|
|
byteArrayEqual);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
if (classSuper(t, class_)) {
|
2007-07-05 02:25:25 +00:00
|
|
|
addInterfaces(t, classSuper(t, class_), map);
|
2007-06-16 21:39:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned count = s.read2();
|
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
2007-06-21 01:38:02 +00:00
|
|
|
object name = arrayBody(t, pool, s.read2() - 1);
|
2007-07-05 02:25:25 +00:00
|
|
|
PROTECT(t, name);
|
|
|
|
|
|
|
|
object interface = resolveClass(t, name);
|
|
|
|
PROTECT(t, interface);
|
|
|
|
|
|
|
|
hashMapInsertOrReplace(t, map, name, interface, byteArrayHash,
|
|
|
|
byteArrayEqual);
|
|
|
|
|
|
|
|
addInterfaces(t, interface, map);
|
2007-06-16 21:39:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object interfaceTable = 0;
|
|
|
|
if (hashMapSize(t, map)) {
|
2007-07-05 02:25:25 +00:00
|
|
|
unsigned length = hashMapSize(t, map) ;
|
|
|
|
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
|
|
|
|
length *= 2;
|
|
|
|
}
|
|
|
|
interfaceTable = makeArray(t, length, true);
|
2007-06-17 23:25:58 +00:00
|
|
|
PROTECT(t, interfaceTable);
|
|
|
|
|
2007-06-16 21:39:05 +00:00
|
|
|
unsigned i = 0;
|
2007-06-18 04:09:02 +00:00
|
|
|
object it = hashMapIterator(t, map);
|
2007-06-17 23:25:58 +00:00
|
|
|
PROTECT(t, it);
|
|
|
|
|
2007-06-18 04:09:02 +00:00
|
|
|
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;
|
|
|
|
|
2007-06-18 21:13:21 +00:00
|
|
|
set(t, arrayBody(t, interfaceTable, i++), interface);
|
2007-06-17 23:25:58 +00:00
|
|
|
|
2007-07-05 02:25:25 +00:00
|
|
|
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
|
|
|
|
// we'll fill in this table in parseMethodTable():
|
|
|
|
object vtable = makeArray
|
|
|
|
(t, arrayLength(t, classVirtualTable(t, interface)), true);
|
|
|
|
|
|
|
|
set(t, arrayBody(t, interfaceTable, i++), vtable);
|
|
|
|
}
|
2007-06-16 21:39:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
set(t, classInterfaceTable(t, class_), interfaceTable);
|
|
|
|
}
|
|
|
|
|
2007-06-24 01:39:49 +00:00
|
|
|
inline unsigned
|
2007-06-18 04:09:02 +00:00
|
|
|
fieldSize(Thread* t, object field)
|
|
|
|
{
|
2007-06-24 01:39:49 +00:00
|
|
|
unsigned code = fieldCode(t, field);
|
|
|
|
if (code == ObjectField) {
|
2007-06-20 04:26:36 +00:00
|
|
|
return BytesPerWord;
|
2007-06-24 01:39:49 +00:00
|
|
|
} else {
|
2007-06-24 19:57:00 +00:00
|
|
|
return primitiveSize(t, code);
|
2007-06-18 04:09:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-16 21:39:05 +00:00
|
|
|
void
|
|
|
|
parseFieldTable(Thread* t, Stream& s, object class_, object pool)
|
|
|
|
{
|
|
|
|
PROTECT(t, class_);
|
|
|
|
PROTECT(t, pool);
|
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
unsigned memberOffset = BytesPerWord;
|
|
|
|
if (classSuper(t, class_)) {
|
2007-06-22 20:55:11 +00:00
|
|
|
memberOffset = classFixedSize(t, classSuper(t, class_));
|
2007-06-21 18:35:24 +00:00
|
|
|
}
|
|
|
|
|
2007-06-16 21:39:05 +00:00
|
|
|
unsigned count = s.read2();
|
|
|
|
if (count) {
|
|
|
|
unsigned staticOffset = 0;
|
|
|
|
|
2007-06-21 19:43:33 +00:00
|
|
|
object fieldTable = makeArray(t, count, true);
|
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());
|
|
|
|
}
|
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
object field = makeField
|
2007-06-24 01:39:49 +00:00
|
|
|
(t,
|
|
|
|
flags,
|
|
|
|
0, // offset
|
2007-06-24 19:57:00 +00:00
|
|
|
fieldCode(t, byteArrayBody(t, arrayBody(t, pool, spec - 1), 0)),
|
2007-06-24 01:39:49 +00:00
|
|
|
arrayBody(t, pool, name - 1),
|
|
|
|
arrayBody(t, pool, spec - 1),
|
|
|
|
class_);
|
2007-06-16 21:39:05 +00:00
|
|
|
|
|
|
|
if (flags & ACC_STATIC) {
|
2007-06-24 19:57:00 +00:00
|
|
|
fieldOffset(t, field) = staticOffset++;
|
2007-06-16 21:39:05 +00:00
|
|
|
} else {
|
2007-06-20 04:26:36 +00:00
|
|
|
unsigned excess = memberOffset % BytesPerWord;
|
2007-06-24 19:57:00 +00:00
|
|
|
if (excess and fieldCode(t, field) == ObjectField) {
|
2007-06-20 04:26:36 +00:00
|
|
|
memberOffset += BytesPerWord - excess;
|
2007-06-16 21:39:05 +00:00
|
|
|
}
|
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
fieldOffset(t, field) = memberOffset;
|
|
|
|
memberOffset += fieldSize(t, field);
|
2007-06-16 21:39:05 +00:00
|
|
|
}
|
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
set(t, arrayBody(t, fieldTable, i), field);
|
2007-06-16 21:39:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
set(t, classFieldTable(t, class_), fieldTable);
|
|
|
|
|
|
|
|
if (staticOffset) {
|
2007-06-21 19:43:33 +00:00
|
|
|
object staticTable = makeArray(t, staticOffset, true);
|
2007-06-16 21:39:05 +00:00
|
|
|
|
|
|
|
set(t, classStaticTable(t, class_), staticTable);
|
|
|
|
}
|
|
|
|
}
|
2007-06-21 18:35:24 +00:00
|
|
|
|
2007-06-30 01:37:45 +00:00
|
|
|
classFixedSize(t, class_) = pad(memberOffset);
|
2007-06-21 18:35:24 +00:00
|
|
|
|
|
|
|
object mask = makeIntArray
|
2007-06-21 19:43:33 +00:00
|
|
|
(t, divide(classFixedSize(t, class_), BitsPerWord), true);
|
2007-06-30 01:37:45 +00:00
|
|
|
intArrayBody(t, mask, 0) = 1;
|
2007-06-21 18:35:24 +00:00
|
|
|
|
|
|
|
bool sawReferenceField = false;
|
|
|
|
for (object c = class_; c; c = classSuper(t, c)) {
|
|
|
|
object fieldTable = classFieldTable(t, c);
|
|
|
|
if (fieldTable) {
|
|
|
|
for (int i = arrayLength(t, fieldTable) - 1; i >= 0; --i) {
|
|
|
|
object field = arrayBody(t, fieldTable, i);
|
2007-06-24 01:39:49 +00:00
|
|
|
if (fieldCode(t, field) == ObjectField) {
|
2007-06-21 18:35:24 +00:00
|
|
|
unsigned index = fieldOffset(t, field) / BytesPerWord;
|
|
|
|
intArrayBody(t, mask, (index / 32)) |= 1 << (index % 32);
|
|
|
|
sawReferenceField = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sawReferenceField) {
|
|
|
|
set(t, classObjectMask(t, class_), mask);
|
|
|
|
}
|
2007-06-16 21:39:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
2007-06-30 01:37:45 +00:00
|
|
|
object code = makeCode(t, pool, 0, 0, maxStack, maxLocals, length, false);
|
2007-06-18 21:13:21 +00:00
|
|
|
s.read(&codeBody(t, code, 0), length);
|
2007-06-17 23:25:58 +00:00
|
|
|
|
|
|
|
unsigned ehtLength = s.read2();
|
|
|
|
if (ehtLength) {
|
|
|
|
PROTECT(t, code);
|
|
|
|
|
2007-06-21 19:43:33 +00:00
|
|
|
object eht = makeExceptionHandlerTable(t, ehtLength, false);
|
2007-06-17 23:25:58 +00:00
|
|
|
for (unsigned i = 0; i < ehtLength; ++i) {
|
2007-06-18 04:09:02 +00:00
|
|
|
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) {
|
2007-06-30 01:37:45 +00:00
|
|
|
object name = arrayBody(t, pool, s.read2() - 1);
|
|
|
|
unsigned length = s.read4();
|
|
|
|
|
|
|
|
if (strcmp(reinterpret_cast<const int8_t*>("LineNumberTable"),
|
|
|
|
&byteArrayBody(t, name, 0)) == 0)
|
|
|
|
{
|
|
|
|
unsigned lntLength = s.read2();
|
|
|
|
object lnt = makeLineNumberTable(t, lntLength, false);
|
|
|
|
for (unsigned i = 0; i < lntLength; ++i) {
|
|
|
|
LineNumber* ln = lineNumberTableBody(t, lnt, i);
|
|
|
|
lineNumberIp(ln) = s.read2();
|
|
|
|
lineNumberLine(ln) = s.read2();
|
|
|
|
}
|
|
|
|
|
|
|
|
set(t, codeLineNumberTable(t, code), lnt);
|
|
|
|
} else {
|
|
|
|
s.skip(length);
|
|
|
|
}
|
2007-06-17 23:25:58 +00:00
|
|
|
}
|
2007-06-18 04:25:42 +00:00
|
|
|
|
|
|
|
return code;
|
2007-06-16 21:39:05 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
unsigned
|
|
|
|
parameterFootprint(Thread* t, object spec)
|
|
|
|
{
|
|
|
|
unsigned footprint = 0;
|
|
|
|
const char* s = reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0));
|
|
|
|
++ s; // skip '('
|
|
|
|
while (*s and *s != ')') {
|
|
|
|
switch (*s) {
|
|
|
|
case 'L':
|
|
|
|
while (*s and *s != ';') ++ s;
|
|
|
|
++ s;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '[':
|
|
|
|
while (*s == '[') ++ s;
|
2007-07-06 01:06:06 +00:00
|
|
|
switch (*s) {
|
|
|
|
case 'L':
|
|
|
|
while (*s and *s != ';') ++ s;
|
|
|
|
++ s;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
++ s;
|
|
|
|
break;
|
|
|
|
}
|
2007-07-04 02:56:02 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'J':
|
|
|
|
case 'D':
|
|
|
|
++ s;
|
|
|
|
++ footprint;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
++ s;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
++ footprint;
|
|
|
|
}
|
|
|
|
|
|
|
|
return footprint;
|
|
|
|
}
|
|
|
|
|
2007-06-18 04:09:02 +00:00
|
|
|
unsigned
|
|
|
|
parameterCount(Thread* t, object spec)
|
|
|
|
{
|
|
|
|
unsigned count = 0;
|
2007-06-18 21:13:21 +00:00
|
|
|
const char* s = reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0));
|
2007-06-18 04:09:02 +00:00
|
|
|
++ s; // skip '('
|
|
|
|
while (*s and *s != ')') {
|
|
|
|
switch (*s) {
|
|
|
|
case 'L':
|
|
|
|
while (*s and *s != ';') ++ s;
|
|
|
|
++ s;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '[':
|
|
|
|
while (*s == '[') ++ s;
|
2007-07-06 01:06:06 +00:00
|
|
|
switch (*s) {
|
|
|
|
case 'L':
|
|
|
|
while (*s and *s != ';') ++ s;
|
|
|
|
++ s;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
++ s;
|
|
|
|
break;
|
|
|
|
}
|
2007-06-18 04:09:02 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
++ s;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
++ count;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
2007-06-30 01:37:45 +00:00
|
|
|
int
|
|
|
|
lineNumber(Thread* t, object method, unsigned ip)
|
|
|
|
{
|
|
|
|
if (methodFlags(t, method) & ACC_NATIVE) {
|
|
|
|
return NativeLine;
|
|
|
|
}
|
|
|
|
|
|
|
|
object table = codeLineNumberTable(t, methodCode(t, method));
|
|
|
|
if (table) {
|
|
|
|
// todo: do a binary search:
|
|
|
|
int last = UnknownLine;
|
|
|
|
for (unsigned i = 0; i < lineNumberTableLength(t, table); ++i) {
|
|
|
|
if (ip <= lineNumberIp(lineNumberTableBody(t, table, i))) {
|
|
|
|
return last;
|
|
|
|
} else {
|
|
|
|
last = lineNumberLine(lineNumberTableBody(t, table, i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return last;
|
|
|
|
} else {
|
|
|
|
return UnknownLine;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-29 16:42:39 +00:00
|
|
|
unsigned
|
|
|
|
mangledSize(int8_t c)
|
|
|
|
{
|
|
|
|
switch (c) {
|
|
|
|
case '_':
|
|
|
|
case ';':
|
|
|
|
case '[':
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
case '$':
|
|
|
|
return 6;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned
|
|
|
|
mangle(int8_t c, int8_t* dst)
|
|
|
|
{
|
|
|
|
switch (c) {
|
|
|
|
case '/':
|
|
|
|
dst[0] = '_';
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
case '_':
|
|
|
|
dst[0] = '_';
|
|
|
|
dst[1] = '1';
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
case ';':
|
|
|
|
dst[0] = '_';
|
|
|
|
dst[1] = '2';
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
case '[':
|
|
|
|
dst[0] = '_';
|
|
|
|
dst[1] = '3';
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
case '$':
|
|
|
|
memcpy(dst, "_00024", 6);
|
|
|
|
return 6;
|
|
|
|
|
|
|
|
default:
|
|
|
|
dst[0] = c;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
object
|
2007-06-29 16:42:39 +00:00
|
|
|
makeJNIName(Thread* t, object method, bool decorate)
|
2007-06-24 19:57:00 +00:00
|
|
|
{
|
2007-06-29 16:42:39 +00:00
|
|
|
unsigned size = 5;
|
|
|
|
object className = ::className(t, methodClass(t, method));
|
|
|
|
PROTECT(t, className);
|
|
|
|
for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) {
|
|
|
|
size += mangledSize(byteArrayBody(t, className, i));
|
|
|
|
}
|
2007-06-24 21:49:04 +00:00
|
|
|
|
2007-06-29 16:42:39 +00:00
|
|
|
++ size;
|
|
|
|
|
|
|
|
object methodName = ::methodName(t, method);
|
|
|
|
PROTECT(t, methodName);
|
|
|
|
for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) {
|
|
|
|
size += mangledSize(byteArrayBody(t, methodName, i));
|
|
|
|
}
|
|
|
|
|
|
|
|
object methodSpec = ::methodSpec(t, method);
|
|
|
|
PROTECT(t, methodSpec);
|
|
|
|
if (decorate) {
|
|
|
|
size += 2;
|
|
|
|
for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1
|
|
|
|
and byteArrayBody(t, methodSpec, i) != ')'; ++i)
|
|
|
|
{
|
|
|
|
size += mangledSize(byteArrayBody(t, methodSpec, i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object name = makeByteArray(t, size + 1, false);
|
|
|
|
unsigned index = 0;
|
|
|
|
|
|
|
|
memcpy(&byteArrayBody(t, name, index), "Java_", 5);
|
|
|
|
index += 5;
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < byteArrayLength(t, className) - 1; ++i) {
|
|
|
|
index += mangle(byteArrayBody(t, className, i),
|
|
|
|
&byteArrayBody(t, name, index));
|
|
|
|
}
|
|
|
|
|
|
|
|
byteArrayBody(t, name, index++) = '_';
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < byteArrayLength(t, methodName) - 1; ++i) {
|
|
|
|
index += mangle(byteArrayBody(t, methodName, i),
|
|
|
|
&byteArrayBody(t, name, index));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (decorate) {
|
|
|
|
byteArrayBody(t, name, index++) = '_';
|
|
|
|
byteArrayBody(t, name, index++) = '_';
|
|
|
|
for (unsigned i = 1; i < byteArrayLength(t, methodSpec) - 1
|
|
|
|
and byteArrayBody(t, methodSpec, i) != ')'; ++i)
|
|
|
|
{
|
|
|
|
index += mangle(byteArrayBody(t, className, i),
|
|
|
|
&byteArrayBody(t, name, index));
|
2007-06-24 21:49:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-29 16:42:39 +00:00
|
|
|
byteArrayBody(t, name, index++) = 0;
|
|
|
|
|
|
|
|
assert(t, index == size + 1);
|
|
|
|
|
2007-06-24 21:49:04 +00:00
|
|
|
return name;
|
2007-06-24 19:57:00 +00:00
|
|
|
}
|
|
|
|
|
2007-06-16 21:39:05 +00:00
|
|
|
void
|
2007-06-18 04:09:02 +00:00
|
|
|
parseMethodTable(Thread* t, Stream& s, object class_, object pool)
|
2007-06-16 21:39:05 +00:00
|
|
|
{
|
|
|
|
PROTECT(t, class_);
|
|
|
|
PROTECT(t, pool);
|
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
object virtualMap = makeHashMap(t, 0, 0);
|
|
|
|
PROTECT(t, virtualMap);
|
|
|
|
|
|
|
|
object nativeMap = makeHashMap(t, 0, 0);
|
|
|
|
PROTECT(t, nativeMap);
|
2007-06-16 21:39:05 +00:00
|
|
|
|
|
|
|
unsigned virtualCount = 0;
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object superVirtualTable = 0;
|
2007-06-17 22:03:27 +00:00
|
|
|
PROTECT(t, superVirtualTable);
|
2007-06-16 21:39:05 +00:00
|
|
|
|
2007-07-05 02:25:25 +00:00
|
|
|
if (classFlags(t, class_) & ACC_INTERFACE) {
|
|
|
|
object itable = classInterfaceTable(t, class_);
|
|
|
|
if (itable) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, itable); ++i) {
|
|
|
|
object vtable = classVirtualTable(t, arrayBody(t, itable, i));
|
|
|
|
for (unsigned j = 0; j < virtualCount; ++j) {
|
|
|
|
object method = arrayBody(t, vtable, j);
|
|
|
|
if (hashMapInsertOrReplace(t, virtualMap, method, method, methodHash,
|
|
|
|
methodEqual))
|
|
|
|
{
|
|
|
|
++ virtualCount;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (classSuper(t, class_)) {
|
|
|
|
superVirtualTable = classVirtualTable(t, classSuper(t, class_));
|
|
|
|
}
|
2007-06-21 01:38:02 +00:00
|
|
|
|
2007-07-05 02:25:25 +00:00
|
|
|
if (superVirtualTable) {
|
|
|
|
virtualCount = arrayLength(t, superVirtualTable);
|
|
|
|
for (unsigned i = 0; i < virtualCount; ++i) {
|
|
|
|
object method = arrayBody(t, superVirtualTable, i);
|
|
|
|
hashMapInsert(t, virtualMap, method, method, methodHash);
|
|
|
|
}
|
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-21 19:43:33 +00:00
|
|
|
object methodTable = makeArray(t, count, true);
|
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-21 01:38:02 +00:00
|
|
|
object name = arrayBody(t, pool, s.read2() - 1);
|
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"),
|
2007-06-18 21:13:21 +00:00
|
|
|
&byteArrayBody(t, name, 0)) == 0)
|
2007-06-16 21:39:05 +00:00
|
|
|
{
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-24 21:49:04 +00:00
|
|
|
unsigned parameterCount = ::parameterCount
|
|
|
|
(t, arrayBody(t, pool, spec - 1));
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
unsigned parameterFootprint = ::parameterFootprint
|
|
|
|
(t, arrayBody(t, pool, spec - 1));
|
|
|
|
|
2007-06-24 21:49:04 +00:00
|
|
|
if ((flags & ACC_STATIC) == 0) {
|
|
|
|
++ parameterCount;
|
2007-07-04 17:58:27 +00:00
|
|
|
++ parameterFootprint;
|
2007-06-24 21:49:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
object method = makeMethod(t,
|
|
|
|
flags,
|
|
|
|
0, // offset
|
|
|
|
parameterCount,
|
2007-07-04 02:56:02 +00:00
|
|
|
parameterFootprint,
|
2007-06-24 21:49:04 +00:00
|
|
|
arrayBody(t, pool, name - 1),
|
|
|
|
arrayBody(t, pool, spec - 1),
|
|
|
|
class_,
|
|
|
|
code);
|
2007-06-24 19:57:00 +00:00
|
|
|
PROTECT(t, method);
|
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>"),
|
2007-06-24 19:57:00 +00:00
|
|
|
&byteArrayBody(t, methodName(t, method), 0)) == 0)
|
2007-06-17 23:25:58 +00:00
|
|
|
{
|
2007-06-24 19:57:00 +00:00
|
|
|
set(t, classInitializer(t, class_), method);
|
2007-06-17 23:25:58 +00:00
|
|
|
}
|
|
|
|
} else {
|
2007-06-24 19:57:00 +00:00
|
|
|
object p = hashMapFindNode
|
|
|
|
(t, virtualMap, method, methodHash, methodEqual);
|
2007-06-16 21:39:05 +00:00
|
|
|
|
|
|
|
if (p) {
|
2007-06-24 19:57:00 +00:00
|
|
|
methodOffset(t, method) = methodOffset(t, tripleFirst(t, p));
|
2007-06-16 21:39:05 +00:00
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
set(t, tripleSecond(t, p), method);
|
2007-06-16 21:39:05 +00:00
|
|
|
} else {
|
2007-06-24 19:57:00 +00:00
|
|
|
methodOffset(t, method) = virtualCount++;
|
2007-06-16 21:39:05 +00:00
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
listAppend(t, newVirtuals, method);
|
2007-06-16 21:39:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
if (flags & ACC_NATIVE) {
|
|
|
|
object p = hashMapFindNode
|
|
|
|
(t, nativeMap, method, methodHash, methodEqual);
|
|
|
|
|
|
|
|
if (p == 0) {
|
|
|
|
hashMapInsert(t, virtualMap, method, method, methodHash);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
set(t, arrayBody(t, methodTable, i), method);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
|
|
|
object method = arrayBody(t, methodTable, i);
|
|
|
|
|
|
|
|
if (methodFlags(t, method) & ACC_NATIVE) {
|
|
|
|
object p = hashMapFindNode
|
|
|
|
(t, nativeMap, method, methodHash, methodEqual);
|
|
|
|
|
|
|
|
object jniName = makeJNIName(t, method, p != 0);
|
|
|
|
set(t, methodCode(t, method), jniName);
|
|
|
|
}
|
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-07-05 02:25:25 +00:00
|
|
|
unsigned i = 0;
|
2007-06-21 19:43:33 +00:00
|
|
|
object vtable = makeArray(t, virtualCount, false);
|
2007-06-16 21:39:05 +00:00
|
|
|
|
2007-07-05 02:25:25 +00:00
|
|
|
if (classFlags(t, class_) & ACC_INTERFACE) {
|
|
|
|
object it = hashMapIterator(t, virtualMap);
|
|
|
|
|
|
|
|
for (; it; it = hashMapIteratorNext(t, it)) {
|
|
|
|
object method = tripleFirst(t, hashMapIteratorNode(t, it));
|
|
|
|
set(t, arrayBody(t, vtable, i++), method);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (superVirtualTable) {
|
|
|
|
for (; i < arrayLength(t, superVirtualTable); ++i) {
|
|
|
|
object method = arrayBody(t, superVirtualTable, i);
|
|
|
|
method = hashMapFind(t, virtualMap, method, methodHash, methodEqual);
|
2007-06-16 21:39:05 +00:00
|
|
|
|
2007-07-05 02:25:25 +00:00
|
|
|
set(t, arrayBody(t, vtable, i), method);
|
|
|
|
}
|
2007-06-16 21:39:05 +00:00
|
|
|
}
|
2007-06-21 01:38:02 +00:00
|
|
|
}
|
2007-06-16 21:39:05 +00:00
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
for (object p = listFront(t, newVirtuals); p; p = pairSecond(t, p)) {
|
|
|
|
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
|
|
|
|
2007-07-05 02:25:25 +00:00
|
|
|
if ((classFlags(t, class_) & ACC_INTERFACE) == 0) {
|
|
|
|
// generate interface vtables
|
2007-06-17 23:25:58 +00:00
|
|
|
|
2007-07-05 02:25:25 +00:00
|
|
|
object itable = classInterfaceTable(t, class_);
|
|
|
|
if (itable) {
|
|
|
|
PROTECT(t, itable);
|
2007-06-17 23:25:58 +00:00
|
|
|
|
2007-07-05 02:25:25 +00:00
|
|
|
for (unsigned i = 0; i < arrayLength(t, itable); i += 2) {
|
|
|
|
object ivtable = classVirtualTable(t, arrayBody(t, itable, i));
|
|
|
|
object vtable = arrayBody(t, itable, i + 1);
|
2007-06-21 01:38:02 +00:00
|
|
|
|
2007-07-05 02:25:25 +00:00
|
|
|
for (unsigned j = 0; j < arrayLength(t, ivtable); ++j) {
|
|
|
|
object method = arrayBody(t, ivtable, j);
|
|
|
|
method = hashMapFind
|
|
|
|
(t, virtualMap, method, methodHash, methodEqual);
|
2007-06-21 01:38:02 +00:00
|
|
|
|
2007-07-05 02:25:25 +00:00
|
|
|
set(t, arrayBody(t, vtable, j), method);
|
|
|
|
}
|
2007-06-21 01:38:02 +00:00
|
|
|
}
|
2007-06-17 23:25:58 +00:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object pool = parsePool(t, s);
|
2007-06-16 01:02:24 +00:00
|
|
|
|
|
|
|
unsigned flags = s.read2();
|
|
|
|
unsigned name = s.read2();
|
|
|
|
|
|
|
|
object class_ = makeClass(t,
|
2007-06-18 04:09:02 +00:00
|
|
|
flags,
|
2007-07-04 15:56:55 +00:00
|
|
|
0, // VM flags
|
2007-06-16 01:02:24 +00:00
|
|
|
0, // fixed size
|
|
|
|
0, // array size
|
|
|
|
0, // object mask
|
2007-06-21 01:38:02 +00:00
|
|
|
arrayBody(t, pool, name - 1),
|
2007-06-16 21:39:05 +00:00
|
|
|
0, // super
|
|
|
|
0, // interfaces
|
2007-06-18 04:09:02 +00:00
|
|
|
0, // vtable
|
2007-06-16 01:02:24 +00:00
|
|
|
0, // fields
|
|
|
|
0, // methods
|
|
|
|
0, // static table
|
2007-06-18 04:09:02 +00:00
|
|
|
0); // initializer
|
2007-06-16 01:02:24 +00:00
|
|
|
PROTECT(t, class_);
|
2007-06-16 21:39:05 +00:00
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
unsigned super = s.read2();
|
|
|
|
if (super) {
|
|
|
|
object sc = resolveClass(t, arrayBody(t, pool, super - 1));
|
|
|
|
if (UNLIKELY(t->exception)) return 0;
|
2007-06-16 01:02:24 +00:00
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
set(t, classSuper(t, class_), sc);
|
2007-07-04 15:56:55 +00:00
|
|
|
|
|
|
|
classVmFlags(t, class_) |= classVmFlags(t, sc);
|
2007-06-21 01:38:02 +00:00
|
|
|
}
|
2007-06-16 21:39:05 +00:00
|
|
|
|
|
|
|
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-24 19:57:00 +00:00
|
|
|
void
|
|
|
|
updateBootstrapClass(Thread* t, object bootstrapClass, object class_)
|
|
|
|
{
|
|
|
|
expect(t, bootstrapClass != class_);
|
|
|
|
|
|
|
|
// verify that the classes have the same layout
|
|
|
|
expect(t, classSuper(t, bootstrapClass) == classSuper(t, class_));
|
|
|
|
expect(t, classFixedSize(t, bootstrapClass) == classFixedSize(t, class_));
|
|
|
|
expect(t, (classObjectMask(t, bootstrapClass) == 0
|
|
|
|
and classObjectMask(t, class_) == 0)
|
|
|
|
or intArrayEqual(t, classObjectMask(t, bootstrapClass),
|
|
|
|
classObjectMask(t, class_)));
|
|
|
|
|
|
|
|
PROTECT(t, bootstrapClass);
|
|
|
|
PROTECT(t, class_);
|
|
|
|
|
2007-07-02 01:42:35 +00:00
|
|
|
ENTER(t, Thread::ExclusiveState);
|
2007-06-24 19:57:00 +00:00
|
|
|
|
2007-07-04 15:56:55 +00:00
|
|
|
classVmFlags(t, class_) |= classVmFlags(t, bootstrapClass);
|
|
|
|
|
2007-07-02 14:19:05 +00:00
|
|
|
memcpy(bootstrapClass,
|
|
|
|
class_,
|
|
|
|
extendedSize(t, class_, baseSize(t, class_, objectClass(t, class_)))
|
|
|
|
* BytesPerWord);
|
2007-06-24 19:57:00 +00:00
|
|
|
|
2007-06-30 02:38:16 +00:00
|
|
|
object fieldTable = classFieldTable(t, class_);
|
|
|
|
if (fieldTable) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, fieldTable); ++i) {
|
|
|
|
set(t, fieldClass(t, arrayBody(t, fieldTable, i)), bootstrapClass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
object methodTable = classMethodTable(t, class_);
|
|
|
|
if (methodTable) {
|
|
|
|
for (unsigned i = 0; i < arrayLength(t, methodTable); ++i) {
|
|
|
|
set(t, methodClass(t, arrayBody(t, methodTable, i)), bootstrapClass);
|
|
|
|
}
|
|
|
|
}
|
2007-06-24 19:57:00 +00:00
|
|
|
}
|
|
|
|
|
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) {
|
2007-06-20 19:20:25 +00:00
|
|
|
ClassFinder::Data* data = t->vm->classFinder->find
|
|
|
|
(reinterpret_cast<const char*>(&byteArrayBody(t, spec, 0)));
|
2007-06-14 23:55:06 +00:00
|
|
|
|
|
|
|
if (data) {
|
2007-06-29 02:58:48 +00:00
|
|
|
if (Verbose) {
|
|
|
|
fprintf(stderr, "parsing %s\n", &byteArrayBody
|
|
|
|
(t, spec, 0));
|
|
|
|
}
|
2007-06-21 01:38:02 +00:00
|
|
|
|
2007-06-16 01:02:24 +00:00
|
|
|
// parse class file
|
2007-06-20 19:20:25 +00:00
|
|
|
class_ = parseClass(t, data->start(), data->length());
|
|
|
|
data->dispose();
|
2007-06-15 02:03:33 +00:00
|
|
|
|
2007-06-29 02:58:48 +00:00
|
|
|
if (Verbose) {
|
|
|
|
fprintf(stderr, "done parsing %s\n", &byteArrayBody
|
|
|
|
(t, className(t, class_), 0));
|
|
|
|
}
|
2007-06-21 01:38:02 +00:00
|
|
|
|
2007-06-14 23:55:06 +00:00
|
|
|
PROTECT(t, class_);
|
2007-06-16 01:02:24 +00:00
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
object bootstrapClass = hashMapFind
|
|
|
|
(t, t->vm->bootstrapClassMap, spec, byteArrayHash, byteArrayEqual);
|
2007-07-05 02:25:25 +00:00
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
if (bootstrapClass) {
|
|
|
|
PROTECT(t, bootstrapClass);
|
|
|
|
|
|
|
|
updateBootstrapClass(t, bootstrapClass, class_);
|
|
|
|
class_ = bootstrapClass;
|
2007-06-24 01:39:49 +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 {
|
2007-06-18 21:13:21 +00:00
|
|
|
object message = makeString(t, "%s", &byteArrayBody(t, spec, 0));
|
2007-06-14 23:55:06 +00:00
|
|
|
t->exception = makeClassNotFoundException(t, message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return class_;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
|
|
|
resolveClass(Thread* t, object pool, unsigned index)
|
|
|
|
{
|
2007-06-18 21:13:21 +00:00
|
|
|
object o = arrayBody(t, pool, index);
|
2007-07-01 21:34:22 +00:00
|
|
|
if (objectClass(t, o) == arrayBody(t, t->vm->types, Machine::ByteArrayType))
|
|
|
|
{
|
2007-06-14 23:55:06 +00:00
|
|
|
PROTECT(t, pool);
|
|
|
|
|
|
|
|
o = resolveClass(t, o);
|
|
|
|
if (UNLIKELY(t->exception)) return 0;
|
|
|
|
|
2007-06-18 21:13:21 +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-07-01 21:34:22 +00:00
|
|
|
if (objectClass(t, o) == arrayBody(t, t->vm->types, Machine::ByteArrayType))
|
|
|
|
{
|
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;
|
2007-06-14 02:12:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
|
|
|
resolve(Thread* t, object pool, unsigned index,
|
2007-06-14 02:41:59 +00:00
|
|
|
object (*find)(Thread*, object, object))
|
2007-06-14 02:12:28 +00:00
|
|
|
{
|
2007-06-18 21:13:21 +00:00
|
|
|
object o = arrayBody(t, pool, index);
|
2007-07-01 21:34:22 +00:00
|
|
|
if (objectClass(t, o) == arrayBody(t, t->vm->types, Machine::ReferenceType))
|
|
|
|
{
|
2007-06-14 02:41:59 +00:00
|
|
|
PROTECT(t, pool);
|
2007-06-14 02:12:28 +00:00
|
|
|
|
2007-06-14 23:55:06 +00:00
|
|
|
object class_ = resolveClass(t, o, referenceClass);
|
2007-06-14 02:12:28 +00:00
|
|
|
if (UNLIKELY(t->exception)) return 0;
|
|
|
|
|
2007-06-18 21:13:21 +00:00
|
|
|
o = find(t, class_, arrayBody(t, pool, index));
|
2007-06-14 02:12:28 +00:00
|
|
|
if (UNLIKELY(t->exception)) return 0;
|
|
|
|
|
2007-06-18 21:13:21 +00:00
|
|
|
set(t, arrayBody(t, pool, index), o);
|
2007-06-14 02:12:28 +00:00
|
|
|
}
|
2007-06-14 02:41:59 +00:00
|
|
|
return o;
|
2007-06-14 02:12:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
|
|
|
resolveField(Thread* t, object pool, unsigned index)
|
|
|
|
{
|
2007-06-14 02:41:59 +00:00
|
|
|
return resolve(t, pool, index, findFieldInClass);
|
2007-06-14 02:12:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline object
|
|
|
|
resolveMethod(Thread* t, object pool, unsigned index)
|
|
|
|
{
|
2007-06-14 02:41:59 +00:00
|
|
|
return resolve(t, pool, index, findMethodInClass);
|
2007-06-14 02:12:28 +00:00
|
|
|
}
|
|
|
|
|
2007-06-24 21:49:04 +00:00
|
|
|
object
|
|
|
|
makeNativeMethodData(Thread* t, object method, void* function, bool builtin)
|
|
|
|
{
|
|
|
|
PROTECT(t, method);
|
|
|
|
|
|
|
|
object data = makeNativeMethodData(t,
|
|
|
|
function,
|
|
|
|
0, // argument table size
|
|
|
|
0, // return code,
|
|
|
|
builtin,
|
2007-06-29 02:58:48 +00:00
|
|
|
methodParameterCount(t, method) + 1,
|
2007-06-24 21:49:04 +00:00
|
|
|
false);
|
|
|
|
|
2007-06-29 02:58:48 +00:00
|
|
|
unsigned argumentTableSize = BytesPerWord;
|
2007-06-24 21:49:04 +00:00
|
|
|
unsigned index = 0;
|
|
|
|
|
2007-06-29 02:58:48 +00:00
|
|
|
nativeMethodDataParameterTypes(t, data, index++) = POINTER_TYPE;
|
|
|
|
|
2007-06-24 21:49:04 +00:00
|
|
|
if ((methodFlags(t, method) & ACC_STATIC) == 0) {
|
2007-06-29 02:58:48 +00:00
|
|
|
nativeMethodDataParameterTypes(t, data, index++) = POINTER_TYPE;
|
|
|
|
argumentTableSize += BytesPerWord;
|
2007-06-24 21:49:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const char* s = reinterpret_cast<const char*>
|
|
|
|
(&byteArrayBody(t, methodSpec(t, method), 0));
|
|
|
|
++ s; // skip '('
|
|
|
|
while (*s and *s != ')') {
|
|
|
|
unsigned code = fieldCode(t, *s);
|
2007-06-29 02:58:48 +00:00
|
|
|
nativeMethodDataParameterTypes(t, data, index++) = fieldType(t, code);
|
2007-06-24 21:49:04 +00:00
|
|
|
|
|
|
|
switch (*s) {
|
|
|
|
case 'L':
|
2007-06-29 02:58:48 +00:00
|
|
|
argumentTableSize += BytesPerWord;
|
2007-06-24 21:49:04 +00:00
|
|
|
while (*s and *s != ';') ++ s;
|
|
|
|
++ s;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '[':
|
2007-06-29 02:58:48 +00:00
|
|
|
argumentTableSize += BytesPerWord;
|
2007-06-24 21:49:04 +00:00
|
|
|
while (*s == '[') ++ s;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2007-06-29 02:58:48 +00:00
|
|
|
argumentTableSize += pad(primitiveSize(t, code));
|
2007-06-24 21:49:04 +00:00
|
|
|
++ s;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nativeMethodDataArgumentTableSize(t, data) = argumentTableSize;
|
|
|
|
nativeMethodDataReturnCode(t, data) = fieldCode(t, s[1]);
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
2007-06-24 01:39:49 +00:00
|
|
|
inline object
|
|
|
|
resolveNativeMethodData(Thread* t, object method)
|
|
|
|
{
|
2007-07-01 21:34:22 +00:00
|
|
|
if (objectClass(t, methodCode(t, method))
|
2007-06-24 01:39:49 +00:00
|
|
|
== arrayBody(t, t->vm->types, Machine::ByteArrayType))
|
|
|
|
{
|
2007-06-24 21:49:04 +00:00
|
|
|
object data = 0;
|
2007-06-24 19:57:00 +00:00
|
|
|
for (System::Library* lib = t->vm->libraries; lib; lib = lib->next()) {
|
2007-06-24 01:39:49 +00:00
|
|
|
void* p = lib->resolve(reinterpret_cast<const char*>
|
|
|
|
(&byteArrayBody(t, methodCode(t, method), 0)));
|
|
|
|
if (p) {
|
|
|
|
PROTECT(t, method);
|
2007-06-24 21:49:04 +00:00
|
|
|
data = makeNativeMethodData(t, method, p, false);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-06-24 01:39:49 +00:00
|
|
|
|
2007-06-24 21:49:04 +00:00
|
|
|
if (data == 0) {
|
|
|
|
object p = hashMapFind(t, t->vm->builtinMap, methodCode(t, method),
|
|
|
|
byteArrayHash, byteArrayEqual);
|
|
|
|
if (p) {
|
|
|
|
PROTECT(t, method);
|
|
|
|
data = makeNativeMethodData(t, method, pointerValue(t, p), true);
|
|
|
|
}
|
|
|
|
}
|
2007-06-24 01:39:49 +00:00
|
|
|
|
2007-06-25 02:20:35 +00:00
|
|
|
if (LIKELY(data)) {
|
2007-06-24 21:49:04 +00:00
|
|
|
set(t, methodCode(t, method), data);
|
2007-06-25 02:20:35 +00:00
|
|
|
} else {
|
|
|
|
object message = makeString
|
|
|
|
(t, "%s", &byteArrayBody(t, methodCode(t, method), 0));
|
|
|
|
t->exception = makeUnsatisfiedLinkError(t, message);
|
2007-06-24 21:49:04 +00:00
|
|
|
}
|
2007-06-25 02:20:35 +00:00
|
|
|
|
2007-06-24 21:49:04 +00:00
|
|
|
return data;
|
|
|
|
} else {
|
|
|
|
return methodCode(t, method);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-04 17:58:27 +00:00
|
|
|
inline void
|
2007-06-24 21:49:04 +00:00
|
|
|
invokeNative(Thread* t, object method)
|
|
|
|
{
|
|
|
|
object data = resolveNativeMethodData(t, method);
|
2007-06-25 02:20:35 +00:00
|
|
|
if (UNLIKELY(t->exception)) {
|
2007-07-04 17:58:27 +00:00
|
|
|
return;
|
2007-06-24 21:49:04 +00:00
|
|
|
}
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
pushFrame(t, method);
|
|
|
|
|
2007-06-29 02:58:48 +00:00
|
|
|
unsigned count = methodParameterCount(t, method);
|
2007-06-24 01:39:49 +00:00
|
|
|
|
2007-06-29 02:58:48 +00:00
|
|
|
unsigned size = nativeMethodDataArgumentTableSize(t, data);
|
|
|
|
uintptr_t args[size / BytesPerWord];
|
2007-06-24 21:49:04 +00:00
|
|
|
unsigned offset = 0;
|
2007-06-24 01:39:49 +00:00
|
|
|
|
2007-06-29 02:58:48 +00:00
|
|
|
args[offset++] = reinterpret_cast<uintptr_t>(t);
|
2007-06-24 21:49:04 +00:00
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
unsigned sp = frameBase(t, t->frame);
|
2007-06-29 02:58:48 +00:00
|
|
|
for (unsigned i = 0; i < count; ++i) {
|
2007-06-30 01:37:45 +00:00
|
|
|
unsigned type = nativeMethodDataParameterTypes(t, data, i + 1);
|
2007-06-24 21:49:04 +00:00
|
|
|
|
2007-06-29 02:58:48 +00:00
|
|
|
switch (type) {
|
|
|
|
case INT8_TYPE:
|
|
|
|
case INT16_TYPE:
|
|
|
|
case INT32_TYPE:
|
|
|
|
case FLOAT_TYPE:
|
2007-07-04 17:58:27 +00:00
|
|
|
args[offset++] = peekInt(t, sp++);
|
2007-06-29 02:58:48 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case INT64_TYPE:
|
|
|
|
case DOUBLE_TYPE: {
|
2007-07-04 17:58:27 +00:00
|
|
|
uint64_t v = peekLong(t, sp);
|
2007-06-29 02:58:48 +00:00
|
|
|
memcpy(args + offset, &v, 8);
|
|
|
|
offset += (8 / BytesPerWord);
|
2007-07-04 17:58:27 +00:00
|
|
|
sp += 2;
|
2007-06-29 02:58:48 +00:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case POINTER_TYPE:
|
2007-07-04 17:58:27 +00:00
|
|
|
args[offset++] = reinterpret_cast<uintptr_t>
|
|
|
|
(t->stack + ((sp++) * 2) + 1);
|
2007-06-29 02:58:48 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default: abort(t);
|
2007-06-24 01:39:49 +00:00
|
|
|
}
|
2007-06-24 21:49:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned returnCode = nativeMethodDataReturnCode(t, data);
|
2007-06-29 02:58:48 +00:00
|
|
|
unsigned returnType = fieldType(t, returnCode);
|
2007-06-24 21:49:04 +00:00
|
|
|
void* function = nativeMethodDataFunction(t, data);
|
|
|
|
|
|
|
|
bool builtin = nativeMethodDataBuiltin(t, data);
|
|
|
|
if (not builtin) {
|
|
|
|
enter(t, Thread::IdleState);
|
|
|
|
}
|
|
|
|
|
2007-07-04 17:58:27 +00:00
|
|
|
uint64_t result = t->vm->system->call
|
2007-06-29 02:58:48 +00:00
|
|
|
(function,
|
|
|
|
args,
|
|
|
|
&nativeMethodDataParameterTypes(t, data, 0),
|
|
|
|
count + 1,
|
|
|
|
size,
|
|
|
|
returnType);
|
2007-06-24 21:49:04 +00:00
|
|
|
|
|
|
|
if (not builtin) {
|
|
|
|
enter(t, Thread::ActiveState);
|
|
|
|
}
|
2007-06-24 01:39:49 +00:00
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
popFrame(t);
|
|
|
|
|
2007-07-04 17:58:27 +00:00
|
|
|
if (UNLIKELY(t->exception)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (returnCode) {
|
|
|
|
case ByteField:
|
|
|
|
case BooleanField:
|
|
|
|
case CharField:
|
|
|
|
case ShortField:
|
|
|
|
case FloatField:
|
|
|
|
case IntField:
|
|
|
|
pushInt(t, result);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LongField:
|
|
|
|
case DoubleField:
|
|
|
|
pushLong(t, result);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ObjectField:
|
|
|
|
pushObject(t, result == 0 ? 0 :
|
|
|
|
*reinterpret_cast<object*>(static_cast<uintptr_t>(result)));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VoidField:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
abort(t);
|
|
|
|
};
|
2007-07-04 02:56:02 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 17:58:27 +00:00
|
|
|
inline object
|
2007-07-06 01:06:06 +00:00
|
|
|
localObject(Thread* t, unsigned index)
|
2007-07-04 02:56:02 +00:00
|
|
|
{
|
2007-07-06 01:06:06 +00:00
|
|
|
return peekObject(t, frameBase(t, t->frame) + index);
|
2007-07-04 02:56:02 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 17:58:27 +00:00
|
|
|
inline uint32_t
|
2007-07-06 01:06:06 +00:00
|
|
|
localInt(Thread* t, unsigned index)
|
2007-07-04 02:56:02 +00:00
|
|
|
{
|
2007-07-06 01:06:06 +00:00
|
|
|
return peekInt(t, frameBase(t, t->frame) + index);
|
2007-06-24 01:39:49 +00:00
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
inline uint64_t
|
2007-07-06 01:06:06 +00:00
|
|
|
localLong(Thread* t, unsigned index)
|
2007-07-02 13:11:51 +00:00
|
|
|
{
|
2007-07-06 01:06:06 +00:00
|
|
|
return peekLong(t, frameBase(t, t->frame) + index);
|
2007-07-04 02:56:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalObject(Thread* t, unsigned index, object value)
|
2007-07-04 17:58:27 +00:00
|
|
|
{
|
2007-07-06 01:06:06 +00:00
|
|
|
pokeObject(t, frameBase(t, t->frame) + index, value);
|
2007-07-04 17:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalInt(Thread* t, unsigned index, uint32_t value)
|
2007-07-04 02:56:02 +00:00
|
|
|
{
|
2007-07-06 01:06:06 +00:00
|
|
|
pokeInt(t, frameBase(t, t->frame) + index, value);
|
2007-07-04 17:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalLong(Thread* t, unsigned index, uint64_t value)
|
2007-07-04 17:58:27 +00:00
|
|
|
{
|
2007-07-06 01:06:06 +00:00
|
|
|
pokeLong(t, frameBase(t, t->frame) + index, value);
|
2007-07-02 13:11:51 +00:00
|
|
|
}
|
|
|
|
|
2007-06-30 01:37:45 +00:00
|
|
|
namespace builtin {
|
|
|
|
|
2007-06-25 01:34:07 +00:00
|
|
|
void
|
2007-06-30 01:37:45 +00:00
|
|
|
loadLibrary(JNIEnv* e, jstring nameString)
|
2007-06-25 01:34:07 +00:00
|
|
|
{
|
2007-06-25 02:02:24 +00:00
|
|
|
Thread* t = static_cast<Thread*>(e);
|
2007-06-25 01:34:07 +00:00
|
|
|
|
|
|
|
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
|
2007-06-30 01:37:45 +00:00
|
|
|
toString(JNIEnv* e, jobject this_)
|
2007-06-25 01:34:07 +00:00
|
|
|
{
|
2007-06-25 02:02:24 +00:00
|
|
|
Thread* t = static_cast<Thread*>(e);
|
2007-06-25 01:34:07 +00:00
|
|
|
|
|
|
|
object s = makeString
|
|
|
|
(t, "%s@%p",
|
2007-07-01 21:34:22 +00:00
|
|
|
&byteArrayBody(t, className(t, objectClass(t, *this_)), 0),
|
2007-06-25 01:34:07 +00:00
|
|
|
*this_);
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
return pushReference(t, s);
|
2007-06-25 01:34:07 +00:00
|
|
|
}
|
|
|
|
|
2007-06-30 01:37:45 +00:00
|
|
|
jarray
|
|
|
|
trace(JNIEnv* e, jint skipCount)
|
|
|
|
{
|
|
|
|
Thread* t = static_cast<Thread*>(e);
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
int frame = t->frame;
|
|
|
|
while (skipCount-- and frame >= 0) {
|
|
|
|
frame = frameNext(t, frame);
|
|
|
|
}
|
2007-06-30 01:37:45 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
return pushReference(t, makeTrace(t, frame));
|
2007-06-30 01:37:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace builtin
|
|
|
|
|
|
|
|
namespace jni {
|
|
|
|
|
2007-06-25 01:34:07 +00:00
|
|
|
jsize
|
|
|
|
GetStringUTFLength(JNIEnv* e, jstring s)
|
|
|
|
{
|
2007-06-25 02:02:24 +00:00
|
|
|
Thread* t = static_cast<Thread*>(e);
|
|
|
|
|
2007-07-02 01:42:35 +00:00
|
|
|
ENTER(t, Thread::ActiveState);
|
2007-06-25 01:34:07 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2007-06-25 02:02:24 +00:00
|
|
|
Thread* t = static_cast<Thread*>(e);
|
|
|
|
|
2007-07-02 01:42:35 +00:00
|
|
|
ENTER(t, Thread::ActiveState);
|
2007-06-25 01:34:07 +00:00
|
|
|
|
|
|
|
char* chars = 0;
|
|
|
|
if (LIKELY(s)) {
|
2007-07-04 18:15:03 +00:00
|
|
|
chars = static_cast<char*>
|
|
|
|
(t->vm->system->allocate(stringLength(t, *s) + 1));
|
2007-06-25 01:34:07 +00:00
|
|
|
|
|
|
|
memcpy(chars,
|
|
|
|
&byteArrayBody(t, stringBytes(t, *s), stringOffset(t, *s)),
|
|
|
|
stringLength(t, *s));
|
|
|
|
|
|
|
|
chars[stringLength(t, *s)] = 0;
|
|
|
|
} else {
|
|
|
|
t->exception = makeNullPointerException(t);
|
|
|
|
}
|
|
|
|
|
2007-06-30 01:37:45 +00:00
|
|
|
if (isCopy) *isCopy = true;
|
2007-06-25 01:34:07 +00:00
|
|
|
return chars;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ReleaseStringUTFChars(JNIEnv* e, jstring, const char* chars)
|
|
|
|
{
|
2007-06-25 02:02:24 +00:00
|
|
|
static_cast<Thread*>(e)->vm->system->free(chars);
|
|
|
|
}
|
|
|
|
|
2007-06-30 01:37:45 +00:00
|
|
|
} // namespace jni
|
|
|
|
|
2007-06-25 02:02:24 +00:00
|
|
|
Machine::Machine(System* system, Heap* heap, ClassFinder* classFinder):
|
|
|
|
system(system),
|
|
|
|
heap(heap),
|
|
|
|
classFinder(classFinder),
|
|
|
|
rootThread(0),
|
|
|
|
exclusive(0),
|
|
|
|
activeCount(0),
|
|
|
|
liveCount(0),
|
|
|
|
stateLock(0),
|
|
|
|
heapLock(0),
|
|
|
|
classLock(0),
|
2007-07-02 14:19:05 +00:00
|
|
|
finalizerLock(0),
|
2007-06-25 02:02:24 +00:00
|
|
|
libraries(0),
|
|
|
|
classMap(0),
|
|
|
|
bootstrapClassMap(0),
|
|
|
|
builtinMap(0),
|
2007-07-02 01:42:35 +00:00
|
|
|
monitorMap(0),
|
2007-06-25 02:02:24 +00:00
|
|
|
types(0),
|
2007-07-02 14:19:05 +00:00
|
|
|
finalizers(0),
|
|
|
|
doomed(0),
|
2007-07-04 15:56:55 +00:00
|
|
|
weakReferences(0),
|
2007-06-25 02:02:24 +00:00
|
|
|
unsafe(false)
|
|
|
|
{
|
|
|
|
memset(&jniEnvVTable, 0, sizeof(JNIEnvVTable));
|
|
|
|
|
2007-06-30 01:37:45 +00:00
|
|
|
jniEnvVTable.GetStringUTFLength = jni::GetStringUTFLength;
|
|
|
|
jniEnvVTable.GetStringUTFChars = jni::GetStringUTFChars;
|
|
|
|
jniEnvVTable.ReleaseStringUTFChars = jni::ReleaseStringUTFChars;
|
2007-06-25 02:02:24 +00:00
|
|
|
|
|
|
|
if (not system->success(system->make(&stateLock)) or
|
|
|
|
not system->success(system->make(&heapLock)) or
|
2007-07-02 04:03:44 +00:00
|
|
|
not system->success(system->make(&classLock)) or
|
2007-07-02 14:19:05 +00:00
|
|
|
not system->success(system->make(&finalizerLock)))
|
2007-06-25 02:02:24 +00:00
|
|
|
{
|
|
|
|
system->abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Machine::dispose()
|
|
|
|
{
|
|
|
|
stateLock->dispose();
|
|
|
|
heapLock->dispose();
|
|
|
|
classLock->dispose();
|
2007-07-02 14:19:05 +00:00
|
|
|
finalizerLock->dispose();
|
|
|
|
|
2007-06-25 02:20:35 +00:00
|
|
|
if (libraries) {
|
|
|
|
libraries->dispose();
|
|
|
|
}
|
2007-06-25 02:02:24 +00:00
|
|
|
|
|
|
|
if (rootThread) {
|
|
|
|
rootThread->dispose();
|
|
|
|
}
|
2007-06-25 01:34:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Thread::Thread(Machine* m):
|
2007-06-25 02:02:24 +00:00
|
|
|
JNIEnv(&(m->jniEnvVTable)),
|
2007-06-25 01:34:07 +00:00
|
|
|
vm(m),
|
|
|
|
next(0),
|
|
|
|
child(0),
|
|
|
|
state(NoState),
|
|
|
|
thread(0),
|
|
|
|
code(0),
|
|
|
|
exception(0),
|
|
|
|
ip(0),
|
|
|
|
sp(0),
|
2007-07-06 01:06:06 +00:00
|
|
|
frame(-1),
|
2007-06-25 01:34:07 +00:00
|
|
|
heapIndex(0),
|
|
|
|
protector(0),
|
|
|
|
chain(0)
|
|
|
|
{
|
|
|
|
if (m->rootThread == 0) {
|
|
|
|
m->rootThread = this;
|
|
|
|
m->unsafe = true;
|
|
|
|
|
|
|
|
Thread* t = this;
|
|
|
|
|
|
|
|
#include "type-initializations.cpp"
|
|
|
|
|
|
|
|
object arrayClass = arrayBody(t, t->vm->types, Machine::ArrayType);
|
2007-07-01 21:34:22 +00:00
|
|
|
set(t, cast<object>(t->vm->types, 0), arrayClass);
|
2007-06-25 01:34:07 +00:00
|
|
|
|
|
|
|
object classClass = arrayBody(t, m->types, Machine::ClassType);
|
2007-07-01 21:34:22 +00:00
|
|
|
set(t, cast<object>(classClass, 0), classClass);
|
2007-06-25 01:34:07 +00:00
|
|
|
|
|
|
|
object intArrayClass = arrayBody(t, m->types, Machine::IntArrayType);
|
2007-07-01 21:34:22 +00:00
|
|
|
set(t, cast<object>(intArrayClass, 0), classClass);
|
2007-06-25 01:34:07 +00:00
|
|
|
|
|
|
|
m->unsafe = false;
|
|
|
|
|
|
|
|
m->bootstrapClassMap = makeHashMap(this, 0, 0);
|
|
|
|
|
|
|
|
#include "type-java-initializations.cpp"
|
|
|
|
|
2007-07-04 17:58:27 +00:00
|
|
|
classVmFlags(t, arrayBody(t, m->types, Machine::WeakReferenceType))
|
|
|
|
|= WeakReferenceFlag;
|
|
|
|
|
2007-06-25 01:34:07 +00:00
|
|
|
m->classMap = makeHashMap(this, 0, 0);
|
|
|
|
m->builtinMap = makeHashMap(this, 0, 0);
|
2007-07-02 01:42:35 +00:00
|
|
|
m->monitorMap = makeHashMap(this, 0, 0);
|
2007-06-25 01:34:07 +00:00
|
|
|
|
|
|
|
struct {
|
|
|
|
const char* key;
|
|
|
|
void* value;
|
|
|
|
} builtins[] = {
|
|
|
|
{ "Java_java_lang_Object_toString",
|
2007-06-30 01:37:45 +00:00
|
|
|
reinterpret_cast<void*>(builtin::toString) },
|
2007-06-25 02:20:35 +00:00
|
|
|
{ "Java_java_lang_System_loadLibrary",
|
2007-06-30 01:37:45 +00:00
|
|
|
reinterpret_cast<void*>(builtin::loadLibrary) },
|
|
|
|
{ "Java_java_lang_Throwable_trace",
|
|
|
|
reinterpret_cast<void*>(builtin::trace) },
|
2007-06-25 01:34:07 +00:00
|
|
|
{ 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, m->builtinMap, key, value, byteArrayHash);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-21 15:47:44 +00:00
|
|
|
object
|
|
|
|
run(Thread* t)
|
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
unsigned instruction = nop;
|
2007-06-08 14:23:04 +00:00
|
|
|
unsigned& ip = t->ip;
|
|
|
|
unsigned& sp = t->sp;
|
2007-07-06 01:06:06 +00:00
|
|
|
int& frame = t->frame;
|
2007-06-08 14:23:04 +00:00
|
|
|
object& code = t->code;
|
|
|
|
object& exception = t->exception;
|
2007-07-04 02:56:02 +00:00
|
|
|
uintptr_t* stack = t->stack;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-06-18 21:13:21 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
|
|
|
|
2007-05-21 15:47:44 +00:00
|
|
|
loop:
|
2007-07-04 02:56:02 +00:00
|
|
|
instruction = codeBody(t, code, ip++);
|
2007-07-04 17:58:27 +00:00
|
|
|
|
|
|
|
if (DebugRun) {
|
|
|
|
fprintf(stderr, "ip: %d; instruction: 0x%x in %s.%s ",
|
|
|
|
ip - 1,
|
|
|
|
instruction,
|
|
|
|
&byteArrayBody
|
|
|
|
(t, className(t, methodClass(t, frameMethod(t, frame))), 0),
|
|
|
|
&byteArrayBody
|
|
|
|
(t, methodName(t, frameMethod(t, frame)), 0));
|
|
|
|
|
|
|
|
int line = lineNumber(t, frameMethod(t, frame), ip);
|
|
|
|
switch (line) {
|
|
|
|
case NativeLine:
|
|
|
|
fprintf(stderr, "(native)\n");
|
|
|
|
break;
|
|
|
|
case UnknownLine:
|
|
|
|
fprintf(stderr, "(unknown line)\n");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
fprintf(stderr, "(line %d)\n", line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
switch (instruction) {
|
2007-05-21 15:47:44 +00:00
|
|
|
case aaload: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t index = popInt(t);
|
|
|
|
object array = popObject(t);
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(array)) {
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(index >= 0 and
|
|
|
|
static_cast<uint32_t>(index) < objectArrayLength(t, array)))
|
2007-06-08 00:23:12 +00:00
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
pushObject(t, objectArrayBody(t, array, index));
|
2007-05-21 15:47:44 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d not in [0,%d]", index,
|
2007-06-08 00:23:12 +00:00
|
|
|
objectArrayLength(t, array));
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeArrayIndexOutOfBoundsException(t, message);
|
2007-05-21 15:47:44 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
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: {
|
2007-07-04 02:56:02 +00:00
|
|
|
object value = popObject(t);
|
|
|
|
int32_t index = popInt(t);
|
|
|
|
object array = popObject(t);
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(array)) {
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(index >= 0 and
|
|
|
|
static_cast<uint32_t>(index) < objectArrayLength(t, array)))
|
2007-06-08 00:23:12 +00:00
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
set(t, objectArrayBody(t, array, index), value);
|
2007-05-21 15:47:44 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d not in [0,%d]", index,
|
2007-06-08 00:23:12 +00:00
|
|
|
objectArrayLength(t, array));
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeArrayIndexOutOfBoundsException(t, message);
|
2007-05-21 15:47:44 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
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: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushObject(t, 0);
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
case aload: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushObject(t, localObject(t, codeBody(t, code, ip++)));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
case aload_0: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushObject(t, localObject(t, 0));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
case aload_1: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushObject(t, localObject(t, 1));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
case aload_2: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushObject(t, localObject(t, 2));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
case aload_3: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushObject(t, localObject(t, 3));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
|
|
|
case anewarray: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t count = popInt(t);
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(count >= 0)) {
|
2007-06-18 21:13:21 +00:00
|
|
|
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;
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object class_ = resolveClass(t, codePool(t, code), index - 1);
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
object array = makeObjectArray(t, class_, count, true);
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushObject(t, array);
|
2007-05-21 15:47:44 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d", count);
|
2007-06-08 14:23:04 +00:00
|
|
|
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: {
|
2007-07-06 01:06:06 +00:00
|
|
|
popFrame(t);
|
|
|
|
if (frame >= 0) {
|
2007-05-21 15:47:44 +00:00
|
|
|
goto loop;
|
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
switch (instruction) {
|
|
|
|
case areturn:
|
|
|
|
return popObject(t);
|
|
|
|
|
|
|
|
case ireturn:
|
|
|
|
return makeInt(t, popInt(t));
|
|
|
|
|
|
|
|
case lreturn:
|
|
|
|
return makeLong(t, popLong(t));
|
|
|
|
}
|
2007-05-21 15:47:44 +00:00
|
|
|
}
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
|
|
|
case arraylength: {
|
2007-07-04 02:56:02 +00:00
|
|
|
object array = popObject(t);
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(array)) {
|
2007-07-01 21:34:22 +00:00
|
|
|
if (objectClass(t, array)
|
2007-06-18 21:13:21 +00:00
|
|
|
== arrayBody(t, t->vm->types, Machine::ObjectArrayType))
|
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, objectArrayLength(t, array));
|
2007-06-06 00:41:04 +00:00
|
|
|
} else {
|
|
|
|
// for all other array types, the length follow the class pointer.
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, cast<uint32_t>(array, BytesPerWord));
|
2007-06-06 00:41:04 +00:00
|
|
|
}
|
2007-05-21 15:47:44 +00:00
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-21 15:47:44 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
2007-06-03 02:00:23 +00:00
|
|
|
} abort(t);
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
case astore: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalObject(t, codeBody(t, code, ip++), popObject(t));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
case astore_0: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalObject(t, 0, popObject(t));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
case astore_1: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalObject(t, 1, popObject(t));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
case astore_2: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalObject(t, 2, popObject(t));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
case astore_3: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalObject(t, 3, popObject(t));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
|
|
|
case athrow: {
|
2007-07-04 02:56:02 +00:00
|
|
|
exception = popObject(t);
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception == 0)) {
|
|
|
|
exception = makeNullPointerException(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
2007-07-04 02:56:02 +00:00
|
|
|
} goto throw_;
|
2007-05-22 00:05:29 +00:00
|
|
|
|
|
|
|
case baload: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t index = popInt(t);
|
|
|
|
object array = popObject(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(array)) {
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(index >= 0 and
|
|
|
|
static_cast<uint32_t>(index) < byteArrayLength(t, array)))
|
2007-06-08 00:23:12 +00:00
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, byteArrayBody(t, array, index));
|
2007-05-22 00:05:29 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d not in [0,%d]", index,
|
2007-06-08 00:23:12 +00:00
|
|
|
byteArrayLength(t, array));
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeArrayIndexOutOfBoundsException(t, message);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case bastore: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int8_t value = popInt(t);
|
|
|
|
int32_t index = popInt(t);
|
|
|
|
object array = popObject(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(array)) {
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(index >= 0 and
|
|
|
|
static_cast<uint32_t>(index) < byteArrayLength(t, array)))
|
2007-06-08 00:23:12 +00:00
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
byteArrayBody(t, array, index) = value;
|
2007-05-22 00:05:29 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d not in [0,%d]", index,
|
2007-06-08 00:23:12 +00:00
|
|
|
byteArrayLength(t, array));
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeArrayIndexOutOfBoundsException(t, message);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case bipush: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, codeBody(t, code, ip++));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case caload: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t index = popInt(t);
|
|
|
|
object array = popObject(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(array)) {
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(index >= 0 and
|
|
|
|
static_cast<uint32_t>(index) < charArrayLength(t, array)))
|
2007-06-08 00:23:12 +00:00
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, charArrayBody(t, array, index));
|
2007-05-22 00:05:29 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d not in [0,%d]", index,
|
2007-06-08 00:23:12 +00:00
|
|
|
charArrayLength(t, array));
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeArrayIndexOutOfBoundsException(t, message);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case castore: {
|
2007-07-04 02:56:02 +00:00
|
|
|
uint16_t value = popInt(t);
|
|
|
|
int32_t index = popInt(t);
|
|
|
|
object array = popObject(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(array)) {
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(index >= 0 and
|
|
|
|
static_cast<uint32_t>(index) < charArrayLength(t, array)))
|
2007-06-08 00:23:12 +00:00
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
charArrayBody(t, array, index) = value;
|
2007-05-22 00:05:29 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d not in [0,%d]", index,
|
2007-06-08 00:23:12 +00:00
|
|
|
charArrayLength(t, array));
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeArrayIndexOutOfBoundsException(t, message);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case checkcast: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (peekObject(t, sp - 1)) {
|
2007-05-22 00:05:29 +00:00
|
|
|
uint16_t index = (index1 << 8) | index2;
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object class_ = resolveClass(t, codePool(t, code), index - 1);
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (not instanceOf(t, class_, peekObject(t, sp - 1))) {
|
2007-06-08 00:23:12 +00:00
|
|
|
object message = makeString
|
2007-06-08 14:23:04 +00:00
|
|
|
(t, "%s as %s",
|
2007-07-04 02:56:02 +00:00
|
|
|
&byteArrayBody
|
|
|
|
(t, className(t, objectClass(t, peekObject(t, sp - 1))), 0),
|
2007-06-18 21:13:21 +00:00
|
|
|
&byteArrayBody(t, className(t, class_), 0));
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeClassCastException(t, message);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case dup: {
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
|
|
|
fprintf(stderr, "dup\n");
|
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
memcpy(stack + ((sp ) * 2), stack + ((sp - 1) * 2), BytesPerWord * 2);
|
|
|
|
++ sp;
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case dup_x1: {
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
|
|
|
fprintf(stderr, "dup_x1\n");
|
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
memcpy(stack + ((sp ) * 2), stack + ((sp - 1) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp - 1) * 2), stack + ((sp - 2) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp - 2) * 2), stack + ((sp ) * 2), BytesPerWord * 2);
|
|
|
|
++ sp;
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case dup_x2: {
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
|
|
|
fprintf(stderr, "dup_x2\n");
|
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
memcpy(stack + ((sp ) * 2), stack + ((sp - 1) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp - 1) * 2), stack + ((sp - 2) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp - 2) * 2), stack + ((sp - 3) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp - 3) * 2), stack + ((sp ) * 2), BytesPerWord * 2);
|
|
|
|
++ sp;
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case dup2: {
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
|
|
|
fprintf(stderr, "dup2\n");
|
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
memcpy(stack + ((sp + 1) * 2), stack + ((sp - 2) * 2), BytesPerWord * 4);
|
|
|
|
sp += 2;
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case dup2_x1: {
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
|
|
|
fprintf(stderr, "dup2_x1\n");
|
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
memcpy(stack + ((sp + 1) * 2), stack + ((sp - 1) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp ) * 2), stack + ((sp - 2) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp - 1) * 2), stack + ((sp - 3) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp - 3) * 2), stack + ((sp ) * 2), BytesPerWord * 4);
|
|
|
|
sp += 2;
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case dup2_x2: {
|
2007-07-04 17:58:27 +00:00
|
|
|
if (DebugStack) {
|
|
|
|
fprintf(stderr, "dup2_x2\n");
|
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
memcpy(stack + ((sp + 1) * 2), stack + ((sp - 1) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp ) * 2), stack + ((sp - 2) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp - 1) * 2), stack + ((sp - 3) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp - 2) * 2), stack + ((sp - 4) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp - 4) * 2), stack + ((sp ) * 2), BytesPerWord * 4);
|
|
|
|
sp += 2;
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case getfield: {
|
2007-07-04 02:56:02 +00:00
|
|
|
object instance = popObject(t);
|
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(instance)) {
|
2007-06-18 21:13:21 +00:00
|
|
|
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;
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object field = resolveField(t, codePool(t, code), index - 1);
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
switch (fieldCode(t, field)) {
|
|
|
|
case ByteField:
|
|
|
|
case BooleanField:
|
|
|
|
pushInt(t, cast<int8_t>(instance, fieldOffset(t, field)));
|
|
|
|
|
|
|
|
case CharField:
|
|
|
|
case ShortField:
|
|
|
|
pushInt(t, cast<int16_t>(instance, fieldOffset(t, field)));
|
|
|
|
|
|
|
|
case FloatField:
|
|
|
|
case IntField:
|
|
|
|
pushInt(t, cast<int32_t>(instance, fieldOffset(t, field)));
|
|
|
|
|
|
|
|
case DoubleField:
|
|
|
|
case LongField:
|
|
|
|
pushLong(t, cast<int64_t>(instance, fieldOffset(t, field)));
|
|
|
|
|
|
|
|
case ObjectField:
|
|
|
|
pushObject(t, cast<object>(instance, fieldOffset(t, field)));
|
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
2007-05-22 00:05:29 +00:00
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case getstatic: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
2007-05-31 00:29:07 +00:00
|
|
|
uint16_t index = (index1 << 8) | index2;
|
2007-05-25 14:48:07 +00:00
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object field = resolveField(t, codePool(t, code), index - 1);
|
2007-06-08 14:23:04 +00:00
|
|
|
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;
|
2007-05-31 00:29:07 +00:00
|
|
|
ip -= 3;
|
|
|
|
goto invoke;
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
2007-07-04 02:56:02 +00:00
|
|
|
|
|
|
|
object v = arrayBody(t, classStaticTable(t, fieldClass(t, field)),
|
|
|
|
fieldOffset(t, field));
|
|
|
|
|
|
|
|
switch (fieldCode(t, field)) {
|
|
|
|
case ByteField:
|
|
|
|
case BooleanField:
|
|
|
|
case CharField:
|
|
|
|
case ShortField:
|
|
|
|
case FloatField:
|
|
|
|
case IntField:
|
|
|
|
pushInt(t, intValue(t, v));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DoubleField:
|
|
|
|
case LongField:
|
|
|
|
pushLong(t, longValue(t, v));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ObjectField:
|
|
|
|
pushObject(t, v);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case goto_: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-06-21 18:35:24 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case goto_w: {
|
2007-06-18 21:13:21 +00:00
|
|
|
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
|
|
|
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 5) + static_cast<int32_t>
|
2007-06-21 18:35:24 +00:00
|
|
|
(((offset1 << 24) | (offset2 << 16) | (offset3 << 8) | offset4));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case i2b: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, static_cast<int8_t>(popInt(t)));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case i2c: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, static_cast<uint16_t>(popInt(t)));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case i2l: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, popInt(t));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case i2s: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, static_cast<int16_t>(popInt(t)));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iadd: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, a + b);
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iaload: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t index = popInt(t);
|
|
|
|
object array = popObject(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(array)) {
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(index >= 0 and
|
|
|
|
static_cast<uint32_t>(index) < intArrayLength(t, array)))
|
2007-06-08 00:23:12 +00:00
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, intArrayBody(t, array, index));
|
2007-05-22 00:05:29 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d not in [0,%d]", index,
|
2007-06-08 00:23:12 +00:00
|
|
|
intArrayLength(t, array));
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeArrayIndexOutOfBoundsException(t, message);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iand: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, a & b);
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iastore: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t value = popInt(t);
|
|
|
|
int32_t index = popInt(t);
|
|
|
|
object array = popObject(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(array)) {
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(index >= 0 and
|
|
|
|
static_cast<uint32_t>(index) < intArrayLength(t, array)))
|
2007-06-08 00:23:12 +00:00
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
intArrayBody(t, array, index) = value;
|
2007-05-22 00:05:29 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d not in [0,%d]", index,
|
2007-06-08 00:23:12 +00:00
|
|
|
intArrayLength(t, array));
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeArrayIndexOutOfBoundsException(t, message);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iconst_0: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, 0);
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iconst_1: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, 1);
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iconst_2: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, 2);
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iconst_3: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, 3);
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iconst_4: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, 4);
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iconst_5: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, 5);
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case idiv: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, a / b);
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case if_acmpeq: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
|
|
|
if (a == b) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case if_acmpne: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
|
|
|
if (a != b) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case if_icmpeq: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (a == b) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case if_icmpne: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (a != b) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case if_icmpgt: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (a > b) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case if_icmpge: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (a >= b) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case if_icmplt: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (a < b) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case if_icmple: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (a < b) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ifeq: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (popInt(t) == 0) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ifne: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (popInt(t)) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ifgt: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (static_cast<int32_t>(popInt(t)) > 0) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ifge: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (static_cast<int32_t>(popInt(t)) >= 0) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iflt: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (static_cast<int32_t>(popInt(t)) < 0) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ifle: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (static_cast<int32_t>(popInt(t)) <= 0) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ifnonnull: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (popObject(t)) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ifnull: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (popObject(t) == 0) {
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iinc: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t index = codeBody(t, code, ip++);
|
|
|
|
int8_t c = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalInt(t, index, localInt(t, index) + c);
|
2007-07-04 17:58:27 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iload: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushInt(t, localInt(t, codeBody(t, code, ip++)));
|
2007-07-04 17:58:27 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iload_0: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushInt(t, localInt(t, 0));
|
2007-07-04 17:58:27 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iload_1: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushInt(t, localInt(t, 1));
|
2007-07-04 17:58:27 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iload_2: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushInt(t, localInt(t, 2));
|
2007-07-04 17:58:27 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iload_3: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushInt(t, localInt(t, 3));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case imul: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, a * b);
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ineg: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, - popInt(t));
|
2007-05-22 00:05:29 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case instanceof: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (peekObject(t, sp - 1)) {
|
2007-05-22 00:05:29 +00:00
|
|
|
uint16_t index = (index1 << 8) | index2;
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object class_ = resolveClass(t, codePool(t, code), index - 1);
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-05-22 00:05:29 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (instanceOf(t, class_, peekObject(t, sp - 1))) {
|
|
|
|
pushInt(t, 1);
|
2007-05-22 00:05:29 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, 0);
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, 0);
|
2007-05-22 00:05:29 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
2007-05-25 14:48:07 +00:00
|
|
|
case invokeinterface: {
|
2007-06-18 21:13:21 +00:00
|
|
|
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;
|
2007-07-04 02:56:02 +00:00
|
|
|
|
2007-05-30 00:08:10 +00:00
|
|
|
ip += 2;
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object method = resolveMethod(t, codePool(t, code), index - 1);
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
|
|
|
if (LIKELY(peekObject(t, sp - parameterFootprint))) {
|
|
|
|
code = findInterfaceMethod
|
|
|
|
(t, method, peekObject(t, sp - parameterFootprint));
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-05-30 00:08:10 +00:00
|
|
|
|
|
|
|
goto invoke;
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case invokespecial: {
|
2007-06-18 21:13:21 +00:00
|
|
|
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;
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object method = resolveMethod(t, codePool(t, code), index - 1);
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
|
|
|
if (LIKELY(peekObject(t, sp - parameterFootprint))) {
|
2007-07-06 01:06:06 +00:00
|
|
|
object class_ = methodClass(t, frameMethod(t, frame));
|
2007-06-13 14:03:08 +00:00
|
|
|
if (isSpecialMethod(t, method, class_)) {
|
|
|
|
code = findMethod(t, method, classSuper(t, class_));
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-05-30 00:08:10 +00:00
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
code = method;
|
2007-05-30 00:08:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
goto invoke;
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case invokestatic: {
|
2007-06-18 21:13:21 +00:00
|
|
|
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;
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object method = resolveMethod(t, codePool(t, code), index - 1);
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-06-18 04:09:02 +00:00
|
|
|
object clinit = classInitializer(t, methodClass(t, method));
|
2007-06-17 23:25:58 +00:00
|
|
|
if (clinit) {
|
2007-06-18 04:09:02 +00:00
|
|
|
set(t, classInitializer(t, methodClass(t, method)), 0);
|
2007-06-17 23:25:58 +00:00
|
|
|
code = clinit;
|
2007-06-11 23:40:24 +00:00
|
|
|
ip -= 3;
|
2007-05-30 00:08:10 +00:00
|
|
|
goto invoke;
|
|
|
|
}
|
|
|
|
|
2007-06-08 14:23:04 +00:00
|
|
|
code = method;
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto invoke;
|
|
|
|
|
|
|
|
case invokevirtual: {
|
2007-06-18 21:13:21 +00:00
|
|
|
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;
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object method = resolveMethod(t, codePool(t, code), index - 1);
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
|
|
|
if (LIKELY(peekObject(t, sp - parameterFootprint))) {
|
|
|
|
code = findVirtualMethod
|
|
|
|
(t, method, peekObject(t, sp - parameterFootprint));
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-05-30 00:08:10 +00:00
|
|
|
|
|
|
|
goto invoke;
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ior: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, a | b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case irem: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, a % b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ishl: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, a << b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ishr: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, a >> b);
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case istore: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalInt(t, codeBody(t, code, ip++), popInt(t));
|
2007-07-04 02:56:02 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case istore_0: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalInt(t, 0, popInt(t));
|
2007-07-04 02:56:02 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case istore_1: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalInt(t, 1, popInt(t));
|
2007-07-04 02:56:02 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case istore_2: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalInt(t, 2, popInt(t));
|
2007-07-04 02:56:02 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case istore_3: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalInt(t, 3, popInt(t));
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case isub: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, a - b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iushr: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, static_cast<uint32_t>(a >> b));
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ixor: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t b = popInt(t);
|
|
|
|
int32_t a = popInt(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, a ^ b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case jsr: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t offset1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t offset2 = codeBody(t, code, ip++);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, ip);
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int16_t>(((offset1 << 8) | offset2));
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case jsr_w: {
|
2007-06-18 21:13:21 +00:00
|
|
|
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-07-04 02:56:02 +00:00
|
|
|
pushInt(t, ip);
|
2007-06-21 22:50:52 +00:00
|
|
|
ip = (ip - 3) + static_cast<int32_t>
|
|
|
|
((offset1 << 24) | (offset2 << 16) | (offset3 << 8) | offset4);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case l2i: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, static_cast<int32_t>(popLong(t)));
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ladd: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int64_t b = popLong(t);
|
|
|
|
int64_t a = popLong(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, a + b);
|
2007-05-25 14:48:07 +00:00
|
|
|
} goto loop;
|
|
|
|
|
2007-05-30 00:08:10 +00:00
|
|
|
case laload: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t index = popInt(t);
|
|
|
|
object array = popObject(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(array)) {
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(index >= 0 and
|
|
|
|
static_cast<uint32_t>(index) < longArrayLength(t, array)))
|
2007-06-08 00:23:12 +00:00
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, longArrayBody(t, array, index));
|
2007-05-30 00:08:10 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d not in [0,%d]", index,
|
2007-06-08 00:23:12 +00:00
|
|
|
longArrayLength(t, array));
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeArrayIndexOutOfBoundsException(t, message);
|
2007-05-30 00:08:10 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case land: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int64_t b = popLong(t);
|
|
|
|
int64_t a = popLong(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, a & b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lastore: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int64_t value = popLong(t);
|
|
|
|
int32_t index = popInt(t);
|
|
|
|
object array = popObject(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(array)) {
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(index >= 0 and
|
|
|
|
static_cast<uint32_t>(index) < longArrayLength(t, array)))
|
2007-06-08 00:23:12 +00:00
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
longArrayBody(t, array, index) = value;
|
2007-05-30 00:08:10 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d not in [0,%d]", index,
|
2007-06-08 00:23:12 +00:00
|
|
|
longArrayLength(t, array));
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeArrayIndexOutOfBoundsException(t, message);
|
2007-05-30 00:08:10 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lcmp: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int64_t b = popLong(t);
|
|
|
|
int64_t a = popLong(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, a > b ? 1 : a == b ? 0 : -1);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lconst_0: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, 0);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lconst_1: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, 1);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
case ldc:
|
|
|
|
case ldc_w: {
|
|
|
|
uint16_t index;
|
|
|
|
|
|
|
|
if (instruction == ldc) {
|
|
|
|
index = codeBody(t, code, ip++);
|
|
|
|
} else {
|
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
|
|
|
index = (index1 << 8) | index2;
|
|
|
|
}
|
|
|
|
|
|
|
|
object v = arrayBody(t, codePool(t, code), index - 1);
|
|
|
|
|
|
|
|
if (objectClass(t, v) == arrayBody(t, t->vm->types, Machine::IntType)) {
|
|
|
|
pushInt(t, intValue(t, v));
|
|
|
|
} else if (objectClass(t, v)
|
|
|
|
== arrayBody(t, t->vm->types, Machine::StringType))
|
|
|
|
{
|
|
|
|
pushObject(t, v);
|
|
|
|
} else if (objectClass(t, v)
|
|
|
|
== arrayBody(t, t->vm->types, Machine::FloatType))
|
|
|
|
{
|
|
|
|
pushInt(t, floatValue(t, v));
|
|
|
|
}
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ldc2_w: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
object v = arrayBody(t, codePool(t, code), ((index1 << 8) | index2) - 1);
|
|
|
|
|
|
|
|
if (objectClass(t, v) == arrayBody(t, t->vm->types, Machine::LongType)) {
|
|
|
|
pushLong(t, longValue(t, v));
|
|
|
|
} else if (objectClass(t, v)
|
|
|
|
== arrayBody(t, t->vm->types, Machine::DoubleType))
|
|
|
|
{
|
|
|
|
pushLong(t, doubleValue(t, v));
|
|
|
|
}
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
2007-06-18 19:23:44 +00:00
|
|
|
case vm::ldiv: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int64_t b = popLong(t);
|
|
|
|
int64_t a = popLong(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, a / b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
2007-07-04 17:58:27 +00:00
|
|
|
case lload: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushLong(t, localLong(t, codeBody(t, code, ip++)));
|
2007-07-04 17:58:27 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lload_0: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushLong(t, localLong(t, 0));
|
2007-07-04 17:58:27 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lload_1: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushLong(t, localLong(t, 1));
|
2007-07-04 17:58:27 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lload_2: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushLong(t, localLong(t, 2));
|
2007-07-04 17:58:27 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lload_3: {
|
2007-07-06 01:06:06 +00:00
|
|
|
pushLong(t, localLong(t, 3));
|
2007-07-04 17:58:27 +00:00
|
|
|
} goto loop;
|
|
|
|
|
2007-05-30 00:08:10 +00:00
|
|
|
case lmul: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int64_t b = popLong(t);
|
|
|
|
int64_t a = popLong(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, a * b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lneg: {
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, - popInt(t));
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lor: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int64_t b = popLong(t);
|
|
|
|
int64_t a = popLong(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, a | b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lrem: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int64_t b = popLong(t);
|
|
|
|
int64_t a = popLong(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, a % b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lshl: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int64_t b = popLong(t);
|
|
|
|
int64_t a = popLong(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, a << b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lshr: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int64_t b = popLong(t);
|
|
|
|
int64_t a = popLong(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, a >> b);
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lstore: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalLong(t, codeBody(t, code, ip++), popLong(t));
|
2007-07-04 02:56:02 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lstore_0: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalLong(t, 0, popLong(t));
|
2007-07-04 02:56:02 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lstore_1: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalLong(t, 1, popLong(t));
|
2007-07-04 02:56:02 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lstore_2: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalLong(t, 2, popLong(t));
|
2007-07-04 02:56:02 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lstore_3: {
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalLong(t, 3, popLong(t));
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lsub: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int64_t b = popLong(t);
|
|
|
|
int64_t a = popLong(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, a - b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lushr: {
|
2007-07-04 02:56:02 +00:00
|
|
|
uint64_t b = popLong(t);
|
|
|
|
uint64_t a = popLong(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, a >> b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lxor: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int64_t b = popLong(t);
|
|
|
|
int64_t a = popLong(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushLong(t, a ^ b);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
2007-07-02 01:42:35 +00:00
|
|
|
case monitorenter: {
|
2007-07-04 02:56:02 +00:00
|
|
|
object o = popObject(t);
|
2007-07-02 01:42:35 +00:00
|
|
|
if (LIKELY(o)) {
|
|
|
|
objectMonitor(t, o)->acquire(t);
|
|
|
|
} else {
|
|
|
|
exception = makeNullPointerException(t);
|
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case monitorexit: {
|
2007-07-04 02:56:02 +00:00
|
|
|
object o = popObject(t);
|
2007-07-02 01:42:35 +00:00
|
|
|
if (LIKELY(o)) {
|
|
|
|
objectMonitor(t, o)->release(t);
|
|
|
|
} else {
|
|
|
|
exception = makeNullPointerException(t);
|
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
2007-07-01 21:34:22 +00:00
|
|
|
|
2007-05-31 00:29:07 +00:00
|
|
|
case new_: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
2007-05-31 00:29:07 +00:00
|
|
|
uint16_t index = (index1 << 8) | index2;
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object class_ = resolveClass(t, codePool(t, code), index - 1);
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-06-11 23:40:24 +00:00
|
|
|
|
2007-06-18 04:09:02 +00:00
|
|
|
object clinit = classInitializer(t, class_);
|
2007-06-17 23:25:58 +00:00
|
|
|
if (clinit) {
|
2007-06-18 04:09:02 +00:00
|
|
|
set(t, classInitializer(t, class_), 0);
|
2007-06-17 23:25:58 +00:00
|
|
|
code = clinit;
|
2007-05-31 00:29:07 +00:00
|
|
|
ip -= 3;
|
|
|
|
goto invoke;
|
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushObject(t, make(t, class_));
|
2007-05-31 00:29:07 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case newarray: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t count = popInt(t);
|
2007-05-31 00:29:07 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(count >= 0)) {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t type = codeBody(t, code, ip++);
|
2007-05-31 00:29:07 +00:00
|
|
|
|
|
|
|
object array;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case T_BOOLEAN:
|
2007-07-04 02:56:02 +00:00
|
|
|
array = makeBooleanArray(t, count, true);
|
2007-05-31 00:29:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case T_CHAR:
|
2007-07-04 02:56:02 +00:00
|
|
|
array = makeCharArray(t, count, true);
|
2007-05-31 00:29:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case T_FLOAT:
|
2007-07-04 02:56:02 +00:00
|
|
|
array = makeFloatArray(t, count, true);
|
2007-05-31 00:29:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case T_DOUBLE:
|
2007-07-04 02:56:02 +00:00
|
|
|
array = makeDoubleArray(t, count, true);
|
2007-05-31 00:29:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case T_BYTE:
|
2007-07-04 02:56:02 +00:00
|
|
|
array = makeByteArray(t, count, true);
|
2007-05-31 00:29:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case T_SHORT:
|
2007-07-04 02:56:02 +00:00
|
|
|
array = makeShortArray(t, count, true);
|
2007-05-31 00:29:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case T_INT:
|
2007-07-04 02:56:02 +00:00
|
|
|
array = makeIntArray(t, count, true);
|
2007-05-31 00:29:07 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case T_LONG:
|
2007-07-04 02:56:02 +00:00
|
|
|
array = makeLongArray(t, count, true);
|
2007-05-31 00:29:07 +00:00
|
|
|
break;
|
|
|
|
|
2007-06-03 02:00:23 +00:00
|
|
|
default: abort(t);
|
2007-05-31 00:29:07 +00:00
|
|
|
}
|
2007-06-21 19:43:33 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushObject(t, array);
|
2007-05-31 00:29:07 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d", count);
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNegativeArrayStoreException(t, message);
|
2007-05-31 00:29:07 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case nop: goto loop;
|
|
|
|
|
2007-06-25 02:02:24 +00:00
|
|
|
case pop_: {
|
2007-06-08 14:23:04 +00:00
|
|
|
-- sp;
|
2007-05-31 00:29:07 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case pop2: {
|
2007-07-04 02:56:02 +00:00
|
|
|
sp -= 2;
|
2007-05-31 00:29:07 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case putfield: {
|
2007-07-04 02:56:02 +00:00
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
|
|
|
uint16_t index = (index1 << 8) | index2;
|
2007-05-31 00:29:07 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
object field = resolveField(t, codePool(t, code), index - 1);
|
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-05-31 00:29:07 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
switch (fieldCode(t, field)) {
|
|
|
|
case ByteField:
|
|
|
|
case BooleanField:
|
|
|
|
case CharField:
|
|
|
|
case ShortField:
|
|
|
|
case FloatField:
|
|
|
|
case IntField: {
|
|
|
|
int32_t value = popInt(t);
|
|
|
|
object o = popObject(t);
|
|
|
|
if (LIKELY(o)) {
|
|
|
|
switch (fieldCode(t, field)) {
|
|
|
|
case ByteField:
|
|
|
|
case BooleanField:
|
|
|
|
cast<int8_t>(o, fieldOffset(t, field)) = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CharField:
|
|
|
|
case ShortField:
|
|
|
|
cast<int16_t>(o, fieldOffset(t, field)) = value;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FloatField:
|
|
|
|
case IntField:
|
|
|
|
cast<int32_t>(o, fieldOffset(t, field)) = value;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
exception = makeNullPointerException(t);
|
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case DoubleField:
|
|
|
|
case LongField: {
|
|
|
|
int64_t value = popLong(t);
|
|
|
|
object o = popObject(t);
|
|
|
|
if (LIKELY(o)) {
|
|
|
|
cast<int64_t>(o, fieldOffset(t, field)) = value;
|
|
|
|
} else {
|
|
|
|
exception = makeNullPointerException(t);
|
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ObjectField: {
|
|
|
|
object value = popObject(t);
|
|
|
|
object o = popObject(t);
|
|
|
|
if (LIKELY(o)) {
|
|
|
|
set(t, cast<object>(o, fieldOffset(t, field)), value);
|
|
|
|
} else {
|
|
|
|
exception = makeNullPointerException(t);
|
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} break;
|
|
|
|
|
|
|
|
default: abort(t);
|
2007-05-31 00:29:07 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case putstatic: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
2007-05-31 00:29:07 +00:00
|
|
|
uint16_t index = (index1 << 8) | index2;
|
|
|
|
|
2007-06-21 01:38:02 +00:00
|
|
|
object field = resolveField(t, codePool(t, code), index - 1);
|
2007-06-08 14:23:04 +00:00
|
|
|
if (UNLIKELY(exception)) goto throw_;
|
2007-05-31 00:29: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;
|
2007-05-31 00:29:07 +00:00
|
|
|
ip -= 3;
|
|
|
|
goto invoke;
|
|
|
|
}
|
2007-07-04 02:56:02 +00:00
|
|
|
|
|
|
|
PROTECT(t, field);
|
2007-05-31 00:29:07 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
object v;
|
|
|
|
|
|
|
|
switch (fieldCode(t, field)) {
|
|
|
|
case ByteField:
|
|
|
|
case BooleanField:
|
|
|
|
case CharField:
|
|
|
|
case ShortField:
|
|
|
|
case FloatField:
|
|
|
|
case IntField: {
|
|
|
|
v = makeInt(t, popInt(t));
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case DoubleField:
|
|
|
|
case LongField: {
|
|
|
|
v = makeLong(t, popLong(t));
|
|
|
|
} break;
|
|
|
|
|
|
|
|
case ObjectField:
|
|
|
|
v = popObject(t);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default: abort(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
set(t, arrayBody(t, classStaticTable(t, fieldClass(t, field)),
|
|
|
|
fieldOffset(t, field)), v);
|
2007-05-31 00:29:07 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ret: {
|
2007-07-06 01:06:06 +00:00
|
|
|
ip = localInt(t, codeBody(t, code, ip));
|
2007-05-31 00:29:07 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case return_: {
|
2007-07-06 01:06:06 +00:00
|
|
|
popFrame(t);
|
|
|
|
if (frame >= 0) {
|
2007-05-31 00:29:07 +00:00
|
|
|
goto loop;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case saload: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int32_t index = popInt(t);
|
|
|
|
object array = popObject(t);
|
2007-05-31 00:29:07 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(array)) {
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(index >= 0 and
|
|
|
|
static_cast<uint32_t>(index) < shortArrayLength(t, array)))
|
2007-06-08 00:23:12 +00:00
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, shortArrayBody(t, array, index));
|
2007-05-31 00:29:07 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d not in [0,%d]", index,
|
2007-06-08 00:23:12 +00:00
|
|
|
shortArrayLength(t, array));
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeArrayIndexOutOfBoundsException(t, message);
|
2007-05-31 00:29:07 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-31 00:29:07 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case sastore: {
|
2007-07-04 02:56:02 +00:00
|
|
|
int16_t value = popInt(t);
|
|
|
|
int32_t index = popInt(t);
|
|
|
|
object array = popObject(t);
|
2007-05-31 00:29:07 +00:00
|
|
|
|
2007-06-08 00:23:12 +00:00
|
|
|
if (LIKELY(array)) {
|
2007-07-04 02:56:02 +00:00
|
|
|
if (LIKELY(index >= 0 and
|
|
|
|
static_cast<uint32_t>(index) < shortArrayLength(t, array)))
|
2007-06-08 00:23:12 +00:00
|
|
|
{
|
2007-07-04 02:56:02 +00:00
|
|
|
shortArrayBody(t, array, index) = value;
|
2007-05-31 00:29:07 +00:00
|
|
|
} else {
|
2007-07-04 02:56:02 +00:00
|
|
|
object message = makeString(t, "%d not in [0,%d]", index,
|
2007-06-08 00:23:12 +00:00
|
|
|
shortArrayLength(t, array));
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeArrayIndexOutOfBoundsException(t, message);
|
2007-05-31 00:29:07 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} else {
|
2007-06-08 14:23:04 +00:00
|
|
|
exception = makeNullPointerException(t);
|
2007-05-31 00:29:07 +00:00
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case sipush: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t byte1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t byte2 = codeBody(t, code, ip++);
|
2007-05-31 00:29:07 +00:00
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushInt(t, (byte1 << 8) | byte2);
|
2007-05-31 00:29:07 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case swap: {
|
2007-07-04 02:56:02 +00:00
|
|
|
uintptr_t tmp[2];
|
|
|
|
memcpy(tmp , stack + ((sp - 1) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp - 1) * 2), stack + ((sp - 2) * 2), BytesPerWord * 2);
|
|
|
|
memcpy(stack + ((sp - 2) * 2), tmp , BytesPerWord * 2);
|
2007-05-31 00:29:07 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case wide: goto wide;
|
|
|
|
|
2007-06-03 02:00:23 +00:00
|
|
|
default: abort(t);
|
2007-05-31 00:29:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
wide:
|
2007-06-18 21:13:21 +00:00
|
|
|
switch (codeBody(t, code, ip++)) {
|
2007-07-04 02:56:02 +00:00
|
|
|
case aload: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
2007-05-31 00:29:07 +00:00
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
pushObject(t, localObject(t, (index1 << 8) | index2));
|
2007-05-31 00:29:07 +00:00
|
|
|
} goto loop;
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
case astore: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
2007-05-31 00:29:07 +00:00
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalObject(t, (index1 << 8) | index2, popObject(t));
|
2007-05-31 00:29:07 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iinc: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
2007-05-31 00:29:07 +00:00
|
|
|
uint16_t index = (index1 << 8) | index2;
|
|
|
|
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t count1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t count2 = codeBody(t, code, ip++);
|
2007-05-31 00:29:07 +00:00
|
|
|
uint16_t count = (count1 << 8) | count2;
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalInt(t, index, localInt(t, index) + count);
|
2007-07-04 02:56:02 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case iload: {
|
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
pushInt(t, localInt(t, (index1 << 8) | index2));
|
2007-07-04 02:56:02 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case istore: {
|
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalInt(t, (index1 << 8) | index2, popInt(t));
|
2007-07-04 02:56:02 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lload: {
|
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
pushLong(t, localLong(t, (index1 << 8) | index2));
|
2007-07-04 02:56:02 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case lstore: {
|
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
setLocalLong(t, (index1 << 8) | index2, popLong(t));
|
2007-05-31 00:29:07 +00:00
|
|
|
} goto loop;
|
|
|
|
|
|
|
|
case ret: {
|
2007-06-18 21:13:21 +00:00
|
|
|
uint8_t index1 = codeBody(t, code, ip++);
|
|
|
|
uint8_t index2 = codeBody(t, code, ip++);
|
2007-05-31 00:29:07 +00:00
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
ip = localInt(t, (index1 << 8) | index2);
|
2007-05-30 00:08:10 +00:00
|
|
|
} goto loop;
|
|
|
|
|
2007-06-03 02:00:23 +00:00
|
|
|
default: abort(t);
|
2007-05-30 00:08:10 +00:00
|
|
|
}
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
invoke: {
|
2007-06-24 19:57:00 +00:00
|
|
|
if (methodFlags(t, code) & ACC_NATIVE) {
|
2007-07-04 17:58:27 +00:00
|
|
|
invokeNative(t, code);
|
2007-06-24 01:39:49 +00:00
|
|
|
|
2007-06-24 21:49:04 +00:00
|
|
|
if (UNLIKELY(exception)) {
|
|
|
|
goto throw_;
|
2007-06-24 01:39:49 +00:00
|
|
|
}
|
|
|
|
} else {
|
2007-07-06 01:06:06 +00:00
|
|
|
unsigned parameterFootprint = methodParameterFootprint(t, code);
|
|
|
|
unsigned base = sp - parameterFootprint;
|
2007-07-06 01:10:23 +00:00
|
|
|
if (UNLIKELY(base
|
|
|
|
+ codeMaxLocals(t, methodCode(t, code))
|
|
|
|
+ FrameFootprint
|
|
|
|
+ codeMaxStack(t, methodCode(t, code))
|
2007-07-04 04:13:52 +00:00
|
|
|
> Thread::StackSizeInWords / 2))
|
2007-06-25 02:20:35 +00:00
|
|
|
{
|
|
|
|
exception = makeStackOverflowError(t);
|
|
|
|
goto throw_;
|
|
|
|
}
|
|
|
|
|
2007-07-06 01:06:06 +00:00
|
|
|
pushFrame(t, code);
|
2007-06-24 19:57:00 +00:00
|
|
|
}
|
|
|
|
} goto loop;
|
2007-05-21 15:47:44 +00:00
|
|
|
|
|
|
|
throw_:
|
2007-07-06 01:06:06 +00:00
|
|
|
for (; frame >= 0; frame = frameNext(t, frame)) {
|
2007-06-08 14:23:04 +00:00
|
|
|
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-07-05 02:44:01 +00:00
|
|
|
if (frameIp(t, frame) >= exceptionHandlerStart(eh)
|
|
|
|
and frameIp(t, frame) >= exceptionHandlerEnd(eh))
|
2007-05-25 14:48:07 +00:00
|
|
|
{
|
2007-07-05 02:44:01 +00:00
|
|
|
object catchType = 0;
|
|
|
|
if (exceptionHandlerCatchType(eh)) {
|
|
|
|
catchType = arrayBody
|
|
|
|
(t, codePool(t, code), exceptionHandlerCatchType(eh) - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (catchType == 0 or
|
|
|
|
(objectClass(t, catchType)
|
|
|
|
== arrayBody(t, t->vm->types, Machine::ClassType) and
|
|
|
|
instanceOf(t, catchType, exception)))
|
|
|
|
{
|
2007-07-06 01:06:06 +00:00
|
|
|
sp = frameBase(t, frame);
|
2007-07-05 02:44:01 +00:00
|
|
|
ip = exceptionHandlerIp(eh);
|
|
|
|
pushObject(t, exception);
|
|
|
|
exception = 0;
|
|
|
|
goto loop;
|
|
|
|
}
|
2007-05-21 15:47:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
for (object e = exception; e; e = throwableCause(t, e)) {
|
|
|
|
if (e == exception) {
|
|
|
|
fprintf(stderr, "uncaught exception: ");
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "caused by: ");
|
2007-06-21 01:38:02 +00:00
|
|
|
}
|
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
fprintf(stderr, "%s", &byteArrayBody
|
2007-07-01 21:34:22 +00:00
|
|
|
(t, className(t, objectClass(t, exception)), 0));
|
2007-06-24 19:57:00 +00:00
|
|
|
|
|
|
|
if (throwableMessage(t, exception)) {
|
2007-06-30 02:45:45 +00:00
|
|
|
object m = throwableMessage(t, exception);
|
|
|
|
char message[stringLength(t, m) + 1];
|
|
|
|
memcpy(message,
|
|
|
|
&byteArrayBody(t, stringBytes(t, m), stringOffset(t, m)),
|
|
|
|
stringLength(t, m));
|
|
|
|
message[stringLength(t, m)] = 0;
|
|
|
|
fprintf(stderr, ": %s\n", message);
|
2007-06-30 01:37:45 +00:00
|
|
|
} else {
|
|
|
|
fprintf(stderr, "\n");
|
2007-06-24 19:57:00 +00:00
|
|
|
}
|
2007-06-21 01:38:02 +00:00
|
|
|
|
2007-06-30 01:37:45 +00:00
|
|
|
object trace = throwableTrace(t, e);
|
|
|
|
for (unsigned i = 0; i < objectArrayLength(t, trace); ++i) {
|
|
|
|
object e = objectArrayBody(t, trace, i);
|
|
|
|
const int8_t* class_ = &byteArrayBody
|
|
|
|
(t, className(t, methodClass(t, stackTraceElementMethod(t, e))), 0);
|
|
|
|
const int8_t* method = &byteArrayBody
|
|
|
|
(t, methodName(t, stackTraceElementMethod(t, e)), 0);
|
|
|
|
int line = lineNumber
|
|
|
|
(t, stackTraceElementMethod(t, e), stackTraceElementIp(t, e));
|
|
|
|
|
2007-07-01 21:34:22 +00:00
|
|
|
fprintf(stderr, " at %s.%s ", class_, method);
|
2007-06-30 01:37:45 +00:00
|
|
|
|
|
|
|
switch (line) {
|
|
|
|
case NativeLine:
|
|
|
|
fprintf(stderr, "(native)\n");
|
|
|
|
break;
|
|
|
|
case UnknownLine:
|
2007-07-01 21:34:22 +00:00
|
|
|
fprintf(stderr, "(unknown line)\n");
|
2007-06-30 01:37:45 +00:00
|
|
|
break;
|
|
|
|
default:
|
2007-07-01 21:34:22 +00:00
|
|
|
fprintf(stderr, "(line %d)\n", line);
|
2007-06-30 01:37:45 +00:00
|
|
|
}
|
2007-06-21 01:38:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-24 19:57:00 +00:00
|
|
|
return 0;
|
2007-05-21 15:47:44 +00:00
|
|
|
}
|
|
|
|
|
2007-06-18 21:13:21 +00:00
|
|
|
void
|
|
|
|
run(Thread* t, const char* className, int argc, const char** argv)
|
|
|
|
{
|
2007-06-21 18:35:24 +00:00
|
|
|
enter(t, Thread::ActiveState);
|
|
|
|
|
2007-06-18 21:13:21 +00:00
|
|
|
object class_ = resolveClass(t, makeByteArray(t, "%s", className));
|
|
|
|
if (LIKELY(t->exception == 0)) {
|
|
|
|
PROTECT(t, class_);
|
|
|
|
|
|
|
|
object name = makeByteArray(t, "main");
|
|
|
|
PROTECT(t, name);
|
|
|
|
|
|
|
|
object spec = makeByteArray(t, "([Ljava/lang/String;)V");
|
|
|
|
object reference = makeReference(t, class_, name, spec);
|
|
|
|
|
|
|
|
object method = findMethodInClass(t, class_, reference);
|
|
|
|
if (LIKELY(t->exception == 0)) {
|
|
|
|
object args = makeObjectArray
|
2007-06-21 19:43:33 +00:00
|
|
|
(t, arrayBody(t, t->vm->types, Machine::StringType), argc, true);
|
|
|
|
|
2007-06-18 21:13:21 +00:00
|
|
|
PROTECT(t, args);
|
|
|
|
|
|
|
|
for (int i = 0; i < argc; ++i) {
|
|
|
|
object arg = makeString(t, "%s", argv);
|
|
|
|
set(t, objectArrayBody(t, args, i), arg);
|
|
|
|
}
|
|
|
|
|
2007-07-04 02:56:02 +00:00
|
|
|
pushObject(t, args);
|
2007-07-06 01:06:06 +00:00
|
|
|
pushFrame(t, method);
|
2007-06-18 21:13:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
run(t);
|
|
|
|
}
|
|
|
|
|
2007-05-21 15:47:44 +00:00
|
|
|
} // namespace
|
2007-06-18 21:13:21 +00:00
|
|
|
|
|
|
|
namespace vm {
|
|
|
|
|
|
|
|
void
|
2007-06-20 16:58:35 +00:00
|
|
|
run(System* system, Heap* heap, ClassFinder* classFinder,
|
2007-06-18 21:13:21 +00:00
|
|
|
const char* className, int argc, const char** argv)
|
|
|
|
{
|
2007-06-20 16:58:35 +00:00
|
|
|
Machine m(system, heap, classFinder);
|
|
|
|
Thread t(&m);
|
2007-06-18 21:13:21 +00:00
|
|
|
|
|
|
|
run(&t, className, argc, argv);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|