corda/src/compile.cpp

5310 lines
122 KiB
C++
Raw Normal View History

/* Copyright (c) 2008, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#include "machine.h"
2007-12-09 22:45:43 +00:00
#include "util.h"
#include "vector.h"
#include "process.h"
2008-02-11 17:21:41 +00:00
#include "assembler.h"
2007-12-09 22:45:43 +00:00
#include "compiler.h"
2008-06-04 22:21:27 +00:00
#include "arch.h"
using namespace vm;
extern "C" uint64_t
2007-12-09 22:45:43 +00:00
vmInvoke(void* thread, void* function, void* stack, unsigned stackSize,
unsigned returnType);
2007-10-04 03:19:39 +00:00
extern "C" void
vmCall();
namespace {
const bool Verbose = false;
const bool DebugNatives = false;
const bool DebugCallTable = false;
const bool DebugMethodTree = false;
const bool DebugFrameMaps = false;
2007-12-11 23:52:28 +00:00
const bool CheckArrayBounds = true;
2007-12-09 22:45:43 +00:00
class MyThread: public Thread {
public:
class CallTrace {
public:
CallTrace(MyThread* t):
t(t),
2008-08-16 17:45:36 +00:00
frame(t->frame),
nativeMethod(0),
2007-12-09 22:45:43 +00:00
next(t->trace)
{
t->trace = this;
2008-08-16 17:45:36 +00:00
t->frame = 0;
2007-12-09 22:45:43 +00:00
}
2007-09-30 15:52:21 +00:00
2007-12-09 22:45:43 +00:00
~CallTrace() {
2008-08-16 17:45:36 +00:00
t->frame = frame;
2007-12-09 22:45:43 +00:00
t->trace = next;
}
2007-09-25 23:53:11 +00:00
2007-12-09 22:45:43 +00:00
MyThread* t;
2007-12-30 22:24:48 +00:00
void* ip;
2008-08-16 17:45:36 +00:00
void* frame;
object nativeMethod;
2007-12-09 22:45:43 +00:00
CallTrace* next;
};
2007-12-09 22:45:43 +00:00
MyThread(Machine* m, object javaThread, Thread* parent):
Thread(m, javaThread, parent),
2007-12-30 22:24:48 +00:00
ip(0),
2008-08-16 17:45:36 +00:00
frame(0),
2007-12-09 22:45:43 +00:00
trace(0),
reference(0)
2007-10-03 00:22:48 +00:00
{ }
2007-12-30 22:24:48 +00:00
void* ip;
2008-08-16 17:45:36 +00:00
void* frame;
2007-12-09 22:45:43 +00:00
CallTrace* trace;
Reference* reference;
};
object
resolveThisPointer(MyThread* t, void* stack, object method)
2007-12-09 22:45:43 +00:00
{
return reinterpret_cast<object*>(stack)[methodParameterFootprint(t, method)];
}
2007-12-23 19:26:35 +00:00
object
resolveTarget(MyThread* t, void* stack, object method)
{
object class_ = objectClass(t, resolveThisPointer(t, stack, method));
2007-10-03 00:22:48 +00:00
if (classVmFlags(t, class_) & BootstrapFlag) {
PROTECT(t, method);
PROTECT(t, class_);
resolveClass(t, className(t, class_));
if (UNLIKELY(t->exception)) return 0;
2007-10-03 00:22:48 +00:00
}
if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) {
return findInterfaceMethod(t, method, class_);
} else {
return findMethod(t, method, class_);
}
2007-12-09 22:45:43 +00:00
}
2007-10-03 00:22:48 +00:00
object&
methodTree(MyThread* t);
2007-12-09 22:45:43 +00:00
object
methodTreeSentinal(MyThread* t);
2007-10-03 00:22:48 +00:00
intptr_t
compareIpToMethodBounds(Thread* t, intptr_t ip, object method)
{
intptr_t start = reinterpret_cast<intptr_t>
(&singletonValue(t, methodCompiled(t, method), 0));
if (DebugMethodTree) {
2008-04-16 05:26:58 +00:00
fprintf(stderr, "find 0x%"LX" in (0x%"LX",0x%"LX")\n", ip, start,
start + (singletonCount(t, methodCompiled(t, method))
* BytesPerWord));
}
if (ip < start) {
return -1;
2008-04-11 23:01:17 +00:00
} else if (ip < start + static_cast<intptr_t>
(singletonCount(t, methodCompiled(t, method))
* BytesPerWord))
{
return 0;
} else {
return 1;
}
}
object
methodForIp(MyThread* t, void* ip)
{
if (DebugMethodTree) {
fprintf(stderr, "query for method containing %p\n", ip);
}
return treeQuery(t, methodTree(t), reinterpret_cast<intptr_t>(ip),
methodTreeSentinal(t), compareIpToMethodBounds);
}
2007-10-03 00:22:48 +00:00
2007-12-09 22:45:43 +00:00
class MyStackWalker: public Processor::StackWalker {
public:
2008-04-23 16:33:31 +00:00
enum State {
Start,
Next,
Method,
NativeMethod,
Finish
};
2007-12-09 22:45:43 +00:00
class MyProtector: public Thread::Protector {
public:
MyProtector(MyStackWalker* walker):
Protector(walker->t), walker(walker)
{ }
2007-10-03 00:22:48 +00:00
2007-12-09 22:45:43 +00:00
virtual void visit(Heap::Visitor* v) {
v->visit(&(walker->method_));
2007-12-09 22:45:43 +00:00
}
2007-10-03 00:22:48 +00:00
2007-12-09 22:45:43 +00:00
MyStackWalker* walker;
};
MyStackWalker(MyThread* t):
t(t),
2008-04-23 16:33:31 +00:00
state(Start),
ip_(t->ip),
2007-12-09 22:45:43 +00:00
base(t->base),
stack(t->stack),
trace(t->trace),
2008-04-23 16:33:31 +00:00
method_(0),
2007-12-09 22:45:43 +00:00
protector(this)
{ }
MyStackWalker(MyStackWalker* w):
t(w->t),
2008-04-23 16:33:31 +00:00
state(w->state),
ip_(w->ip_),
2007-12-09 22:45:43 +00:00
base(w->base),
stack(w->stack),
trace(w->trace),
method_(w->method_),
2007-12-09 22:45:43 +00:00
protector(this)
{ }
2007-12-09 22:45:43 +00:00
virtual void walk(Processor::StackVisitor* v) {
2008-04-23 16:33:31 +00:00
for (MyStackWalker it(this); it.valid();) {
MyStackWalker walker(it);
if (not v->visit(&walker)) {
break;
}
it.next();
}
2008-04-23 16:33:31 +00:00
}
bool valid() {
while (true) {
// fprintf(stderr, "state: %d\n", state);
switch (state) {
case Start:
if (ip_ == 0 and stack) {
ip_ = *static_cast<void**>(stack);
}
2008-04-23 16:33:31 +00:00
if (trace and trace->nativeMethod) {
method_ = trace->nativeMethod;
state = NativeMethod;
} else if (ip_) {
state = Next;
} else {
state = Finish;
}
break;
2007-12-09 22:45:43 +00:00
2008-04-23 16:33:31 +00:00
case Next:
if (stack) {
method_ = methodForIp(t, ip_);
if (method_) {
state = Method;
} else if (trace) {
base = trace->base;
stack = static_cast<void**>(trace->stack);
ip_ = (stack ? *static_cast<void**>(stack) : 0);
if (trace->nativeMethod) {
method_ = trace->nativeMethod;
state = NativeMethod;
} else {
trace = trace->next;
state = Next;
}
} else {
state = Finish;
}
} else {
state = Finish;
}
2007-12-09 22:45:43 +00:00
break;
2008-04-23 16:33:31 +00:00
case Method:
case NativeMethod:
return true;
case Finish:
return false;
default:
abort(t);
2007-12-09 22:45:43 +00:00
}
}
}
2008-04-23 16:33:31 +00:00
void next() {
switch (state) {
case Method:
2007-12-09 22:45:43 +00:00
stack = static_cast<void**>(base) + 1;
2008-04-23 16:33:31 +00:00
ip_ = (stack ? *static_cast<void**>(stack) : 0);
2007-12-09 22:45:43 +00:00
base = *static_cast<void**>(base);
2008-04-23 16:33:31 +00:00
state = Next;
break;
2008-04-23 16:33:31 +00:00
case NativeMethod:
trace = trace->next;
2008-04-23 16:33:31 +00:00
state = Next;
break;
default:
abort(t);
}
}
2007-12-09 22:45:43 +00:00
virtual object method() {
2008-04-23 16:33:31 +00:00
switch (state) {
case Method:
return method_;
2008-04-23 16:33:31 +00:00
case NativeMethod:
return trace->nativeMethod;
default:
abort(t);
2007-12-09 22:45:43 +00:00
}
2007-10-03 00:22:48 +00:00
}
2007-12-09 22:45:43 +00:00
virtual int ip() {
2008-04-23 16:33:31 +00:00
switch (state) {
case Method:
return reinterpret_cast<intptr_t>(ip_) - reinterpret_cast<intptr_t>
(&singletonValue(t, methodCompiled(t, method_), 0));
2008-04-23 16:33:31 +00:00
case NativeMethod:
return 0;
default:
abort(t);
2007-10-03 00:22:48 +00:00
}
}
2007-12-09 22:45:43 +00:00
virtual unsigned count() {
2008-04-23 16:33:31 +00:00
unsigned count = 0;
2007-12-09 22:45:43 +00:00
2008-04-23 16:33:31 +00:00
for (MyStackWalker walker(this); walker.valid();) {
walker.next();
++ count;
}
2007-12-09 22:45:43 +00:00
2008-04-23 16:33:31 +00:00
return count;
2007-10-03 00:22:48 +00:00
}
2007-12-09 22:45:43 +00:00
MyThread* t;
2008-04-23 16:33:31 +00:00
State state;
void* ip_;
2007-12-09 22:45:43 +00:00
void* base;
void* stack;
MyThread::CallTrace* trace;
object method_;
2007-12-09 22:45:43 +00:00
MyProtector protector;
};
int
localOffset(MyThread* t, int v, object method)
{
int parameterFootprint = methodParameterFootprint(t, method) * BytesPerWord;
v *= BytesPerWord;
if (v < parameterFootprint) {
return (parameterFootprint - v - BytesPerWord) + (BytesPerWord * 2);
} else {
return -(v + BytesPerWord - parameterFootprint);
2007-10-03 00:22:48 +00:00
}
2007-12-09 22:45:43 +00:00
}
2007-10-03 00:22:48 +00:00
inline object*
localObject(MyThread* t, void* base, object method, unsigned index)
{
return reinterpret_cast<object*>
(static_cast<uint8_t*>(base) + localOffset(t, index, method));
}
2007-12-09 22:45:43 +00:00
class PoolElement {
public:
PoolElement(object value, Promise* address, PoolElement* next):
value(value), address(address), next(next)
2007-12-16 00:24:15 +00:00
{ }
2007-12-09 22:45:43 +00:00
object value;
2007-12-16 00:24:15 +00:00
Promise* address;
PoolElement* next;
2007-12-09 22:45:43 +00:00
};
class Context;
2008-02-11 17:21:41 +00:00
class TraceElement: public TraceHandler {
2007-12-09 22:45:43 +00:00
public:
TraceElement(Context* context, object target,
bool virtualCall, TraceElement* next):
context(context),
address(0),
target(target),
virtualCall(virtualCall),
next(next)
{ }
2007-12-09 22:45:43 +00:00
virtual void handleTrace(Promise* address) {
if (this->address == 0) {
this->address = address;
}
}
Context* context;
Promise* address;
2007-12-09 22:45:43 +00:00
object target;
bool virtualCall;
TraceElement* next;
uintptr_t map[0];
2007-10-03 00:22:48 +00:00
};
2008-01-07 14:51:07 +00:00
enum Event {
2008-07-05 20:21:13 +00:00
PushContextEvent,
PopContextEvent,
2008-01-07 14:51:07 +00:00
PushEvent,
PopEvent,
IpEvent,
MarkEvent,
ClearEvent,
TraceEvent
};
unsigned
localSize(MyThread* t, object method)
{
unsigned size = codeMaxLocals(t, methodCode(t, method));
if ((methodFlags(t, method) & (ACC_SYNCHRONIZED | ACC_STATIC))
== ACC_SYNCHRONIZED)
{
++ size;
}
return size;
}
2008-01-07 14:51:07 +00:00
unsigned
2008-07-05 20:21:13 +00:00
alignedFrameSize(MyThread* t, object method)
2008-01-07 14:51:07 +00:00
{
2008-07-05 20:21:13 +00:00
return Assembler::alignFrameSize
(localSize(t, method) + codeMaxStack(t, methodCode(t, method)));
2008-01-07 14:51:07 +00:00
}
unsigned
frameMapSizeInWords(MyThread* t, object method)
{
2008-07-05 20:21:13 +00:00
return ceiling(alignedFrameSize(t, method), BitsPerWord) * BytesPerWord;
2008-01-07 14:51:07 +00:00
}
uint16_t*
makeVisitTable(MyThread* t, Zone* zone, object method)
{
unsigned size = codeLength(t, methodCode(t, method)) * 2;
uint16_t* table = static_cast<uint16_t*>(zone->allocate(size));
memset(table, 0, size);
return table;
}
uintptr_t*
makeRootTable(MyThread* t, Zone* zone, object method)
2008-01-07 14:51:07 +00:00
{
unsigned size = frameMapSizeInWords(t, method)
* codeLength(t, methodCode(t, method))
* BytesPerWord;
uintptr_t* table = static_cast<uintptr_t*>(zone->allocate(size));
memset(table, 0xFF, size);
2008-01-07 14:51:07 +00:00
return table;
}
enum Thunk {
#define THUNK(s) s##Thunk,
#include "thunks.cpp"
#undef THUNK
};
const unsigned ThunkCount = gcIfNecessaryThunk + 1;
intptr_t
getThunk(MyThread* t, Thunk thunk);
class Context {
2007-10-10 22:39:40 +00:00
public:
2007-12-09 22:45:43 +00:00
class MyProtector: public Thread::Protector {
public:
2008-02-11 17:21:41 +00:00
MyProtector(Context* c): Protector(c->thread), c(c) { }
2007-12-09 22:45:43 +00:00
virtual void visit(Heap::Visitor* v) {
v->visit(&(c->method));
2007-12-09 22:45:43 +00:00
for (PoolElement* p = c->objectPool; p; p = p->next) {
v->visit(&(p->value));
}
2007-12-09 22:45:43 +00:00
for (TraceElement* p = c->traceLog; p; p = p->next) {
v->visit(&(p->target));
2007-12-09 22:45:43 +00:00
}
}
Context* c;
2007-10-10 22:39:40 +00:00
};
class MyClient: public Compiler::Client {
public:
MyClient(MyThread* t): t(t) { }
virtual intptr_t getThunk(UnaryOperation, unsigned) {
abort(t);
}
virtual intptr_t getThunk(BinaryOperation op, unsigned size) {
switch (op) {
case Divide:
if (size == 8) {
return ::getThunk(t, divideLongThunk);
}
break;
case Remainder:
if (size == 8) {
return ::getThunk(t, moduloLongThunk);
}
break;
default: break;
}
abort(t);
}
MyThread* t;
};
Context(MyThread* t, object method):
2008-02-11 17:21:41 +00:00
thread(t),
2008-04-13 18:15:04 +00:00
zone(t->m->system, t->m->heap, 16 * 1024),
2008-02-11 17:21:41 +00:00
assembler(makeAssembler(t->m->system, t->m->heap, &zone)),
client(t),
compiler(makeCompiler(t->m->system, assembler, &zone, &client)),
2007-10-10 22:39:40 +00:00
method(method),
objectPool(0),
traceLog(0),
traceLogCount(0),
2008-01-07 14:51:07 +00:00
visitTable(makeVisitTable(t, &zone, method)),
rootTable(makeRootTable(t, &zone, method)),
eventLog(t->m->system, t->m->heap, 1024),
protector(this)
{ }
Context(MyThread* t):
2008-02-11 17:21:41 +00:00
thread(t),
2008-04-13 18:15:04 +00:00
zone(t->m->system, t->m->heap, LikelyPageSizeInBytes),
2008-02-11 17:21:41 +00:00
assembler(makeAssembler(t->m->system, t->m->heap, &zone)),
client(t),
2008-02-11 17:21:41 +00:00
compiler(0),
method(0),
objectPool(0),
traceLog(0),
traceLogCount(0),
2008-01-07 14:51:07 +00:00
visitTable(0),
rootTable(0),
eventLog(t->m->system, t->m->heap, 0),
protector(this)
{ }
~Context() {
if (compiler) compiler->dispose();
2008-02-11 17:21:41 +00:00
assembler->dispose();
}
2008-02-11 17:21:41 +00:00
MyThread* thread;
Zone zone;
2008-02-11 17:21:41 +00:00
Assembler* assembler;
MyClient client;
2008-02-11 17:21:41 +00:00
Compiler* compiler;
object method;
PoolElement* objectPool;
TraceElement* traceLog;
unsigned traceLogCount;
2008-01-07 14:51:07 +00:00
uint16_t* visitTable;
uintptr_t* rootTable;
bool dirtyRoots;
2008-01-07 14:51:07 +00:00
Vector eventLog;
MyProtector protector;
};
class Frame {
public:
2008-02-11 17:21:41 +00:00
enum StackType {
Integer,
Long,
Object
};
Frame(Context* context, uint8_t* stackMap):
context(context),
2008-02-11 17:21:41 +00:00
t(context->thread),
c(context->compiler),
2008-01-07 14:51:07 +00:00
stackMap(stackMap),
2007-12-09 22:45:43 +00:00
ip(0),
sp(localSize()),
2008-01-07 14:51:07 +00:00
level(0)
2007-12-09 22:45:43 +00:00
{
2008-02-11 17:21:41 +00:00
memset(stackMap, 0, codeMaxStack(t, methodCode(t, context->method)));
2007-12-09 22:45:43 +00:00
}
2008-02-11 17:21:41 +00:00
Frame(Frame* f, uint8_t* stackMap):
context(f->context),
2008-02-11 17:21:41 +00:00
t(context->thread),
c(context->compiler),
2008-01-07 14:51:07 +00:00
stackMap(stackMap),
2007-12-09 22:45:43 +00:00
ip(f->ip),
2008-01-07 14:51:07 +00:00
sp(f->sp),
level(f->level + 1)
2007-12-09 22:45:43 +00:00
{
2008-02-11 17:21:41 +00:00
c->pushState();
memcpy(stackMap, f->stackMap, codeMaxStack
(t, methodCode(t, context->method)));
2008-01-07 14:51:07 +00:00
if (level > 1) {
2008-07-05 20:21:13 +00:00
context->eventLog.append(PushContextEvent);
2008-01-07 14:51:07 +00:00
}
}
~Frame() {
if (t->exception == 0) {
if (level > 0) {
c->saveStack();
c->popState();
c->resetStack();
}
2008-02-11 17:21:41 +00:00
if (level > 1) {
2008-07-05 20:21:13 +00:00
context->eventLog.append(PopContextEvent);
}
2008-01-07 14:51:07 +00:00
}
2007-10-10 22:39:40 +00:00
}
2008-02-11 17:21:41 +00:00
Compiler::Operand* append(object o) {
2007-12-16 00:24:15 +00:00
Promise* p = c->poolAppend(0);
context->objectPool = new
(context->zone.allocate(sizeof(PoolElement)))
PoolElement(o, p, context->objectPool);
2008-02-11 17:21:41 +00:00
return c->address(p);
2007-10-10 22:39:40 +00:00
}
2008-01-07 14:51:07 +00:00
unsigned localSize() {
return ::localSize(t, context->method);
2007-12-09 22:45:43 +00:00
}
2008-01-07 14:51:07 +00:00
unsigned stackSize() {
return codeMaxStack(t, methodCode(t, context->method));
}
2008-01-07 14:51:07 +00:00
unsigned frameSize() {
return localSize() + stackSize();
2007-12-09 22:45:43 +00:00
}
2008-02-11 17:21:41 +00:00
void set(unsigned index, uint8_t type) {
2008-01-07 14:51:07 +00:00
assert(t, index < frameSize());
2007-10-10 22:39:40 +00:00
2008-02-11 17:21:41 +00:00
if (type == Object) {
context->eventLog.append(MarkEvent);
context->eventLog.append2(index);
} else {
context->eventLog.append(ClearEvent);
context->eventLog.append2(index);
2008-01-07 14:51:07 +00:00
}
int si = index - localSize();
if (si >= 0) {
2008-02-11 17:21:41 +00:00
stackMap[si] = type;
2008-01-07 14:51:07 +00:00
}
2007-10-10 22:39:40 +00:00
}
2008-02-11 17:21:41 +00:00
uint8_t get(unsigned index) {
2008-01-07 14:51:07 +00:00
assert(t, index < frameSize());
int si = index - localSize();
assert(t, si >= 0);
2008-02-11 17:21:41 +00:00
return stackMap[si];
2007-10-10 22:39:40 +00:00
}
void pushedInt() {
2008-01-07 14:51:07 +00:00
assert(t, sp + 1 <= frameSize());
2008-02-11 17:21:41 +00:00
set(sp++, Integer);
}
void pushedLong() {
assert(t, sp + 2 <= frameSize());
set(sp++, Long);
set(sp++, Long);
2007-10-10 22:39:40 +00:00
}
void pushedObject() {
2008-01-07 14:51:07 +00:00
assert(t, sp + 1 <= frameSize());
2008-02-11 17:21:41 +00:00
set(sp++, Object);
2007-12-09 22:45:43 +00:00
}
void popped(unsigned count) {
assert(t, sp >= count);
2008-01-07 14:51:07 +00:00
assert(t, sp - count >= localSize());
while (count) {
2008-02-11 17:21:41 +00:00
set(--sp, Integer);
-- count;
}
}
2007-12-09 22:45:43 +00:00
void poppedInt() {
assert(t, sp >= 1);
2008-01-07 14:51:07 +00:00
assert(t, sp - 1 >= localSize());
2008-02-11 17:21:41 +00:00
assert(t, get(sp - 1) == Integer);
2007-12-09 22:45:43 +00:00
-- sp;
}
2008-02-11 17:21:41 +00:00
void poppedLong() {
assert(t, sp >= 1);
assert(t, sp - 2 >= localSize());
assert(t, get(sp - 1) == Long);
assert(t, get(sp - 2) == Long);
sp -= 2;
}
2007-12-09 22:45:43 +00:00
void poppedObject() {
assert(t, sp >= 1);
2008-01-07 14:51:07 +00:00
assert(t, sp - 1 >= localSize());
2008-02-11 17:21:41 +00:00
assert(t, get(sp - 1) == Object);
set(--sp, Integer);
2007-12-09 22:45:43 +00:00
}
void storedInt(unsigned index) {
2008-01-07 14:51:07 +00:00
assert(t, index < localSize());
2008-02-11 17:21:41 +00:00
set(index, Integer);
}
void storedLong(unsigned index) {
assert(t, index + 1 < localSize());
set(index, Long);
set(index + 1, Long);
2007-12-09 22:45:43 +00:00
}
void storedObject(unsigned index) {
2008-01-07 14:51:07 +00:00
assert(t, index < localSize());
2008-02-11 17:21:41 +00:00
set(index, Object);
2007-10-10 22:39:40 +00:00
}
void dupped() {
2008-01-07 14:51:07 +00:00
assert(t, sp + 1 <= frameSize());
assert(t, sp - 1 >= localSize());
2008-02-11 17:21:41 +00:00
set(sp++, get(sp - 1));
2007-10-10 22:39:40 +00:00
}
void duppedX1() {
2008-01-07 14:51:07 +00:00
assert(t, sp + 1 <= frameSize());
assert(t, sp - 2 >= localSize());
2007-12-09 22:45:43 +00:00
2008-02-11 17:21:41 +00:00
uint8_t b2 = get(sp - 2);
uint8_t b1 = get(sp - 1);
2007-12-09 22:45:43 +00:00
2008-02-11 17:21:41 +00:00
set(sp - 1, b2);
set(sp - 2, b1);
set(sp , b1);
2007-12-09 22:45:43 +00:00
++ sp;
}
void duppedX2() {
2008-01-07 14:51:07 +00:00
assert(t, sp + 1 <= frameSize());
assert(t, sp - 3 >= localSize());
2007-12-09 22:45:43 +00:00
2008-02-11 17:21:41 +00:00
uint8_t b3 = get(sp - 3);
uint8_t b2 = get(sp - 2);
uint8_t b1 = get(sp - 1);
2007-12-09 22:45:43 +00:00
2008-02-11 17:21:41 +00:00
set(sp - 2, b3);
set(sp - 1, b2);
set(sp - 3, b1);
set(sp , b1);
2007-12-09 22:45:43 +00:00
++ sp;
}
void dupped2() {
2008-01-07 14:51:07 +00:00
assert(t, sp + 2 <= frameSize());
assert(t, sp - 2 >= localSize());
2007-12-09 22:45:43 +00:00
2008-02-11 17:21:41 +00:00
uint8_t b2 = get(sp - 2);
uint8_t b1 = get(sp - 1);
2007-12-09 22:45:43 +00:00
2008-02-11 17:21:41 +00:00
set(sp, b2);
set(sp + 1, b1);
2007-12-09 22:45:43 +00:00
sp += 2;
}
void dupped2X1() {
2008-01-07 14:51:07 +00:00
assert(t, sp + 2 <= frameSize());
assert(t, sp - 3 >= localSize());
2007-12-09 22:45:43 +00:00
2008-02-11 17:21:41 +00:00
uint8_t b3 = get(sp - 3);
uint8_t b2 = get(sp - 2);
uint8_t b1 = get(sp - 1);
2007-12-09 22:45:43 +00:00
2008-02-11 17:21:41 +00:00
set(sp - 1, b3);
set(sp - 3, b2);
set(sp , b2);
set(sp - 2, b1);
set(sp + 1, b1);
2007-12-09 22:45:43 +00:00
sp += 2;
}
void dupped2X2() {
2008-01-07 14:51:07 +00:00
assert(t, sp + 2 <= frameSize());
assert(t, sp - 4 >= localSize());
2008-02-11 17:21:41 +00:00
uint8_t b4 = get(sp - 4);
uint8_t b3 = get(sp - 3);
uint8_t b2 = get(sp - 2);
uint8_t b1 = get(sp - 1);
2007-10-10 22:39:40 +00:00
2008-02-11 17:21:41 +00:00
set(sp - 2, b4);
set(sp - 1, b3);
set(sp - 4, b2);
set(sp , b2);
set(sp - 3, b1);
set(sp + 1, b1);
2007-12-09 22:45:43 +00:00
sp += 2;
}
2007-12-09 22:45:43 +00:00
void swapped() {
assert(t, sp - 2 >= localSize());
2007-12-09 22:45:43 +00:00
2008-02-11 17:21:41 +00:00
uint8_t saved = get(sp - 1);
2007-10-10 22:39:40 +00:00
2008-02-11 17:21:41 +00:00
set(sp - 1, get(sp - 2));
set(sp - 2, saved);
2007-10-10 22:39:40 +00:00
}
2008-02-11 17:21:41 +00:00
Compiler::Operand* machineIp(unsigned logicalIp) {
2007-12-16 00:24:15 +00:00
return c->promiseConstant(c->machineIp(logicalIp));
}
2008-01-07 14:51:07 +00:00
void visitLogicalIp(unsigned ip) {
c->visitLogicalIp(ip);
2008-01-07 14:51:07 +00:00
context->eventLog.append(IpEvent);
context->eventLog.append2(ip);
2008-01-07 14:51:07 +00:00
}
2007-12-09 22:45:43 +00:00
void startLogicalIp(unsigned ip) {
c->startLogicalIp(ip);
2008-04-20 05:23:08 +00:00
context->eventLog.append(IpEvent);
context->eventLog.append2(ip);
2007-12-09 22:45:43 +00:00
this->ip = ip;
}
2008-07-05 20:21:13 +00:00
void pushQuiet(unsigned size, Compiler::Operand* o) {
if (size == 8 and BytesPerWord == 8) {
c->push(8);
context->eventLog.append(PushEvent);
context->eventLog.appendAddress(c->top());
}
c->push(size, o);
context->eventLog.append(PushEvent);
context->eventLog.appendAddress(c->top());
}
Compiler::Operand* popQuiet(unsigned size) {
context->eventLog.append(PopEvent);
context->eventLog.appendAddress(c->top());
Compiler::Operand* r = c->pop(8);
if (size == 8 and BytesPerWord == 8) {
context->eventLog.append(PopEvent);
context->eventLog.appendAddress(c->top());
c->pop(8);
}
return r;
}
2008-02-11 17:21:41 +00:00
void pushInt(Compiler::Operand* o) {
2008-07-05 20:21:13 +00:00
pushQuiet(4, o);
2007-12-09 22:45:43 +00:00
pushedInt();
}
2008-02-11 17:21:41 +00:00
void pushAddress(Compiler::Operand* o) {
2008-07-05 20:21:13 +00:00
pushQuiet(BytesPerWord, o);
pushedInt();
}
2008-02-11 17:21:41 +00:00
void pushObject(Compiler::Operand* o) {
2008-07-05 20:21:13 +00:00
pushQuiet(BytesPerWord, o);
2007-12-09 22:45:43 +00:00
pushedObject();
}
void pushObject() {
2008-07-05 20:21:13 +00:00
c->pushed();
2008-07-05 20:21:13 +00:00
context->eventLog.append(PushEvent);
context->eventLog.appendAddress(c->top());
pushedObject();
}
2007-12-16 21:30:19 +00:00
void pushLong(Compiler::Operand* o) {
2008-07-05 20:21:13 +00:00
pushQuiet(8, o);
2008-02-11 17:21:41 +00:00
pushedLong();
}
2007-12-09 22:45:43 +00:00
void pop(unsigned count) {
popped(count);
2008-07-05 20:21:13 +00:00
for (unsigned i = count; i;) {
Compiler::StackElement* s = c->top();
context->eventLog.append(PopEvent);
context->eventLog.appendAddress(s);
c->popped();
i -= c->size(s);
}
}
2008-02-11 17:21:41 +00:00
Compiler::Operand* popInt() {
2007-12-09 22:45:43 +00:00
poppedInt();
2008-07-05 20:21:13 +00:00
return popQuiet(4);
}
2007-12-16 21:30:19 +00:00
Compiler::Operand* peekLong(unsigned index) {
return c->peek(8, index);
2007-12-09 22:45:43 +00:00
}
2008-02-11 17:21:41 +00:00
Compiler::Operand* popLong() {
poppedLong();
2008-07-05 20:21:13 +00:00
return popQuiet(8);
2007-12-09 22:45:43 +00:00
}
2008-02-11 17:21:41 +00:00
Compiler::Operand* popObject() {
2007-12-09 22:45:43 +00:00
poppedObject();
2008-07-05 20:21:13 +00:00
return popQuiet(BytesPerWord);
}
2007-12-09 22:45:43 +00:00
void loadInt(unsigned index) {
2008-01-07 14:51:07 +00:00
assert(t, index < localSize());
pushInt(c->loadLocal(BytesPerWord, index));
2007-10-10 22:39:40 +00:00
}
2007-12-09 22:45:43 +00:00
void loadLong(unsigned index) {
2008-02-11 17:21:41 +00:00
assert(t, index < static_cast<unsigned>(localSize() - 1));
pushLong(c->loadLocal(8, index + 1));
2007-12-09 22:45:43 +00:00
}
2007-12-09 22:45:43 +00:00
void loadObject(unsigned index) {
2008-01-07 14:51:07 +00:00
assert(t, index < localSize());
pushObject(c->loadLocal(BytesPerWord, index));
2007-12-09 22:45:43 +00:00
}
2007-12-09 22:45:43 +00:00
void storeInt(unsigned index) {
c->storeLocal(BytesPerWord, popInt(), index);
2007-12-09 22:45:43 +00:00
storedInt(index);
}
2007-12-09 22:45:43 +00:00
void storeLong(unsigned index) {
c->storeLocal(8, popLong(), index + 1);
2008-02-11 17:21:41 +00:00
storedLong(index);
2007-12-09 22:45:43 +00:00
}
2007-12-09 22:45:43 +00:00
void storeObject(unsigned index) {
c->storeLocal(BytesPerWord, popObject(), index);
2007-12-09 22:45:43 +00:00
storedObject(index);
}
void storeObjectOrAddress(unsigned index) {
2008-07-05 20:21:13 +00:00
c->storeLocal(BytesPerWord, popQuiet(BytesPerWord), index);
assert(t, sp >= 1);
2008-01-07 14:51:07 +00:00
assert(t, sp - 1 >= localSize());
2008-02-11 17:21:41 +00:00
if (get(sp - 1) == Object) {
storedObject(index);
} else {
storedInt(index);
}
2008-01-07 14:51:07 +00:00
popped(1);
2007-12-09 22:45:43 +00:00
}
2007-12-09 22:45:43 +00:00
void dup() {
2008-07-05 20:21:13 +00:00
pushQuiet(BytesPerWord, c->peek(BytesPerWord, 0));
2008-02-11 17:21:41 +00:00
2007-12-09 22:45:43 +00:00
dupped();
}
2007-12-09 22:45:43 +00:00
void dupX1() {
2008-07-05 20:21:13 +00:00
Compiler::Operand* s0 = popQuiet(BytesPerWord);
Compiler::Operand* s1 = popQuiet(BytesPerWord);
2008-02-11 17:21:41 +00:00
2008-07-05 20:21:13 +00:00
pushQuiet(BytesPerWord, s0);
pushQuiet(BytesPerWord, s1);
pushQuiet(BytesPerWord, s0);
2007-12-09 22:45:43 +00:00
duppedX1();
}
2007-12-09 22:45:43 +00:00
void dupX2() {
2008-07-05 20:21:13 +00:00
Compiler::Operand* s0 = popQuiet(BytesPerWord);
2008-02-11 17:21:41 +00:00
if (get(sp - 2) == Long) {
2008-07-05 20:21:13 +00:00
Compiler::Operand* s1 = popQuiet(8);
2008-07-05 20:21:13 +00:00
pushQuiet(BytesPerWord, s0);
pushQuiet(8, s1);
pushQuiet(BytesPerWord, s0);
2008-02-11 17:21:41 +00:00
} else {
2008-07-05 20:21:13 +00:00
Compiler::Operand* s1 = popQuiet(BytesPerWord);
Compiler::Operand* s2 = popQuiet(BytesPerWord);
2008-02-11 17:21:41 +00:00
2008-07-05 20:21:13 +00:00
pushQuiet(BytesPerWord, s0);
pushQuiet(BytesPerWord, s2);
pushQuiet(BytesPerWord, s1);
pushQuiet(BytesPerWord, s0);
2008-02-11 17:21:41 +00:00
}
2007-12-09 22:45:43 +00:00
duppedX2();
2007-10-10 22:39:40 +00:00
}
2007-12-09 22:45:43 +00:00
void dup2() {
2008-02-11 17:21:41 +00:00
if (get(sp - 1) == Long) {
2008-07-05 20:21:13 +00:00
pushQuiet(8, peekLong(0));
2008-02-11 17:21:41 +00:00
} else {
2008-07-05 20:21:13 +00:00
Compiler::Operand* s0 = popQuiet(BytesPerWord);
Compiler::Operand* s1 = popQuiet(BytesPerWord);
2008-02-11 17:21:41 +00:00
2008-07-05 20:21:13 +00:00
pushQuiet(BytesPerWord, s1);
pushQuiet(BytesPerWord, s0);
pushQuiet(BytesPerWord, s1);
pushQuiet(BytesPerWord, s0);
2008-02-11 17:21:41 +00:00
}
2007-12-09 22:45:43 +00:00
dupped2();
}
2007-12-09 22:45:43 +00:00
void dup2X1() {
2008-02-11 17:21:41 +00:00
if (get(sp - 1) == Long) {
2008-07-05 20:21:13 +00:00
Compiler::Operand* s0 = popQuiet(8);
Compiler::Operand* s1 = popQuiet(BytesPerWord);
2008-02-11 17:21:41 +00:00
2008-07-05 20:21:13 +00:00
pushQuiet(8, s0);
pushQuiet(BytesPerWord, s1);
pushQuiet(8, s0);
} else {
2008-07-05 20:21:13 +00:00
Compiler::Operand* s0 = popQuiet(BytesPerWord);
Compiler::Operand* s1 = popQuiet(BytesPerWord);
Compiler::Operand* s2 = popQuiet(BytesPerWord);
pushQuiet(BytesPerWord, s1);
pushQuiet(BytesPerWord, s0);
pushQuiet(BytesPerWord, s2);
pushQuiet(BytesPerWord, s1);
pushQuiet(BytesPerWord, s0);
2008-02-11 17:21:41 +00:00
}
2007-12-09 22:45:43 +00:00
dupped2X1();
}
2007-12-09 22:45:43 +00:00
void dup2X2() {
2008-02-11 17:21:41 +00:00
if (get(sp - 1) == Long) {
2008-07-05 20:21:13 +00:00
Compiler::Operand* s0 = popQuiet(8);
2008-02-11 17:21:41 +00:00
if (get(sp - 3) == Long) {
2008-07-05 20:21:13 +00:00
Compiler::Operand* s1 = popQuiet(8);
2008-07-05 20:21:13 +00:00
pushQuiet(8, s0);
pushQuiet(8, s1);
pushQuiet(8, s0);
2008-02-11 17:21:41 +00:00
} else {
2008-07-05 20:21:13 +00:00
Compiler::Operand* s1 = popQuiet(BytesPerWord);
Compiler::Operand* s2 = popQuiet(BytesPerWord);
2008-02-11 17:21:41 +00:00
2008-07-05 20:21:13 +00:00
pushQuiet(8, s0);
pushQuiet(BytesPerWord, s2);
pushQuiet(BytesPerWord, s1);
pushQuiet(8, s0);
2008-02-11 17:21:41 +00:00
}
} else {
2008-07-05 20:21:13 +00:00
Compiler::Operand* s0 = popQuiet(BytesPerWord);
Compiler::Operand* s1 = popQuiet(BytesPerWord);
Compiler::Operand* s2 = popQuiet(BytesPerWord);
Compiler::Operand* s3 = popQuiet(BytesPerWord);
pushQuiet(BytesPerWord, s1);
pushQuiet(BytesPerWord, s0);
pushQuiet(BytesPerWord, s3);
pushQuiet(BytesPerWord, s2);
pushQuiet(BytesPerWord, s1);
pushQuiet(BytesPerWord, s0);
2008-02-11 17:21:41 +00:00
}
2007-10-02 00:08:17 +00:00
2007-12-09 22:45:43 +00:00
dupped2X2();
}
2007-10-02 00:08:17 +00:00
2007-12-09 22:45:43 +00:00
void swap() {
2008-07-05 20:21:13 +00:00
Compiler::Operand* s0 = popQuiet(BytesPerWord);
Compiler::Operand* s1 = popQuiet(BytesPerWord);
2007-10-02 00:08:17 +00:00
2008-07-05 20:21:13 +00:00
pushQuiet(BytesPerWord, s0);
pushQuiet(BytesPerWord, s1);
2007-10-02 00:08:17 +00:00
2007-12-09 22:45:43 +00:00
swapped();
2007-10-02 00:08:17 +00:00
}
TraceElement* trace(object target, bool virtualCall) {
2008-01-07 14:51:07 +00:00
unsigned mapSize = frameMapSizeInWords(t, context->method);
TraceElement* e = context->traceLog = new
(context->zone.allocate(sizeof(TraceElement) + (mapSize * BytesPerWord)))
TraceElement(context, target, virtualCall, context->traceLog);
++ context->traceLogCount;
2008-01-07 14:51:07 +00:00
context->eventLog.append(TraceEvent);
context->eventLog.appendAddress(e);
return e;
}
2007-12-09 22:45:43 +00:00
Context* context;
2007-12-09 22:45:43 +00:00
MyThread* t;
Compiler* c;
2008-02-11 17:21:41 +00:00
uint8_t* stackMap;
2007-12-09 22:45:43 +00:00
unsigned ip;
unsigned sp;
2008-01-07 14:51:07 +00:00
unsigned level;
2007-12-30 22:24:48 +00:00
};
unsigned
savedTargetIndex(MyThread* t, object method)
{
return codeMaxLocals(t, methodCode(t, method));
}
object
findCallNode(MyThread* t, void* address);
void
insertCallNode(MyThread* t, object node);
void*
findExceptionHandler(Thread* t, object method, void* ip)
{
object table = codeExceptionHandlerTable(t, methodCode(t, method));
if (table) {
object index = arrayBody(t, table, 0);
uint8_t* compiled = reinterpret_cast<uint8_t*>
(&singletonValue(t, methodCompiled(t, method), 0));
for (unsigned i = 0; i < arrayLength(t, table) - 1; ++i) {
unsigned start = intArrayBody(t, index, i * 3);
unsigned end = intArrayBody(t, index, (i * 3) + 1);
unsigned key = difference(ip, compiled) - 1;
if (key >= start and key < end) {
object catchType = arrayBody(t, table, i + 1);
if (catchType == 0 or instanceOf(t, catchType, t->exception)) {
return compiled + intArrayBody(t, index, (i * 3) + 2);
}
}
}
}
return 0;
}
void
findUnwindTarget(MyThread* t, void** targetIp, void** targetBase,
void** targetStack)
2007-09-29 21:08:29 +00:00
{
2007-12-30 22:24:48 +00:00
void* ip = t->ip;
2007-12-09 22:45:43 +00:00
void* base = t->base;
void** stack = static_cast<void**>(t->stack);
2008-04-23 16:33:31 +00:00
if (ip == 0) {
2007-12-30 22:24:48 +00:00
ip = *stack;
}
*targetIp = 0;
while (*targetIp == 0) {
object method = methodForIp(t, ip);
if (method) {
PROTECT(t, method);
void* handler = findExceptionHandler(t, method, ip);
2007-12-09 22:45:43 +00:00
if (handler) {
2007-10-04 22:41:19 +00:00
unsigned parameterFootprint = methodParameterFootprint(t, method);
unsigned localFootprint = localSize(t, method);
2007-10-04 22:41:19 +00:00
stack = static_cast<void**>(base)
- (localFootprint - parameterFootprint);
2007-10-04 22:41:19 +00:00
*(--stack) = t->exception;
t->exception = 0;
*targetIp = handler;
*targetBase = base;
*targetStack = stack;
2007-12-09 22:45:43 +00:00
} else {
if (methodFlags(t, method) & ACC_SYNCHRONIZED) {
object lock;
if (methodFlags(t, method) & ACC_STATIC) {
lock = methodClass(t, method);
} else {
lock = *localObject(t, base, method, savedTargetIndex(t, method));
}
release(t, lock);
}
2007-12-09 22:45:43 +00:00
stack = static_cast<void**>(base) + 1;
2007-12-30 22:24:48 +00:00
ip = *stack;
2007-12-09 22:45:43 +00:00
base = *static_cast<void**>(base);
}
2007-10-12 22:06:33 +00:00
} else {
*targetIp = ip;
*targetBase = base;
*targetStack = stack + 1;
}
}
}
void NO_RETURN
unwind(MyThread* t)
{
void* ip;
void* base;
void* stack;
findUnwindTarget(t, &ip, &base, &stack);
vmJump(ip, base, stack, t);
}
2008-07-05 20:21:13 +00:00
void
2008-01-08 19:36:34 +00:00
tryInitClass(MyThread* t, object class_)
{
initClass(t, class_);
if (UNLIKELY(t->exception)) unwind(t);
}
2008-07-05 20:21:13 +00:00
void*
2007-12-30 22:24:48 +00:00
findInterfaceMethodFromInstance(MyThread* t, object method, object instance)
{
2007-12-30 22:24:48 +00:00
if (instance) {
return &singletonValue
(t, methodCompiled
(t, findInterfaceMethod(t, method, objectClass(t, instance))), 0);
} else {
t->exception = makeNullPointerException(t);
unwind(t);
}
}
2008-07-05 20:21:13 +00:00
intptr_t
compareDoublesG(uint64_t bi, uint64_t ai)
{
double a = bitsToDouble(ai);
double b = bitsToDouble(bi);
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else if (a == b) {
return 0;
} else {
return 1;
}
}
2008-07-05 20:21:13 +00:00
intptr_t
compareDoublesL(uint64_t bi, uint64_t ai)
{
double a = bitsToDouble(ai);
double b = bitsToDouble(bi);
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else if (a == b) {
return 0;
} else {
return -1;
}
}
2008-07-05 20:21:13 +00:00
intptr_t
compareFloatsG(uint32_t bi, uint32_t ai)
{
float a = bitsToFloat(ai);
float b = bitsToFloat(bi);
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else if (a == b) {
return 0;
} else {
return 1;
}
}
2008-07-05 20:21:13 +00:00
intptr_t
compareFloatsL(uint32_t bi, uint32_t ai)
{
float a = bitsToFloat(ai);
float b = bitsToFloat(bi);
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else if (a == b) {
return 0;
} else {
return -1;
}
}
2008-07-05 20:21:13 +00:00
uint64_t
addDouble(uint64_t b, uint64_t a)
{
return doubleToBits(bitsToDouble(a) + bitsToDouble(b));
}
2008-07-05 20:21:13 +00:00
uint64_t
subtractDouble(uint64_t b, uint64_t a)
{
return doubleToBits(bitsToDouble(a) - bitsToDouble(b));
}
2008-07-05 20:21:13 +00:00
uint64_t
multiplyDouble(uint64_t b, uint64_t a)
{
return doubleToBits(bitsToDouble(a) * bitsToDouble(b));
}
2008-07-05 20:21:13 +00:00
uint64_t
divideDouble(uint64_t b, uint64_t a)
{
return doubleToBits(bitsToDouble(a) / bitsToDouble(b));
}
2008-07-05 20:21:13 +00:00
uint64_t
moduloDouble(uint64_t b, uint64_t a)
{
return doubleToBits(fmod(bitsToDouble(a), bitsToDouble(b)));
}
2008-07-05 20:21:13 +00:00
uint64_t
2007-12-09 22:45:43 +00:00
negateDouble(uint64_t a)
{
return doubleToBits(- bitsToDouble(a));
}
2008-07-05 20:21:13 +00:00
uint32_t
2007-12-09 22:45:43 +00:00
doubleToFloat(int64_t a)
{
return floatToBits(static_cast<float>(bitsToDouble(a)));
}
2008-07-05 20:21:13 +00:00
int32_t
2007-12-09 22:45:43 +00:00
doubleToInt(int64_t a)
{
return static_cast<int32_t>(bitsToDouble(a));
}
2008-07-05 20:21:13 +00:00
int64_t
2007-12-09 22:45:43 +00:00
doubleToLong(int64_t a)
{
return static_cast<int64_t>(bitsToDouble(a));
}
2008-07-05 20:21:13 +00:00
uint32_t
addFloat(uint32_t b, uint32_t a)
{
return floatToBits(bitsToFloat(a) + bitsToFloat(b));
}
2008-07-05 20:21:13 +00:00
uint32_t
subtractFloat(uint32_t b, uint32_t a)
{
return floatToBits(bitsToFloat(a) - bitsToFloat(b));
}
2008-07-05 20:21:13 +00:00
uint32_t
multiplyFloat(uint32_t b, uint32_t a)
{
return floatToBits(bitsToFloat(a) * bitsToFloat(b));
}
2008-07-05 20:21:13 +00:00
uint32_t
divideFloat(uint32_t b, uint32_t a)
{
return floatToBits(bitsToFloat(a) / bitsToFloat(b));
}
2008-07-05 20:21:13 +00:00
uint32_t
moduloFloat(uint32_t b, uint32_t a)
{
return floatToBits(fmod(bitsToFloat(a), bitsToFloat(b)));
}
2008-07-05 20:21:13 +00:00
uint32_t
2007-12-09 22:45:43 +00:00
negateFloat(uint32_t a)
{
return floatToBits(- bitsToFloat(a));
}
2008-07-05 20:21:13 +00:00
int64_t
divideLong(int64_t b, int64_t a)
{
return a / b;
}
2008-07-05 20:21:13 +00:00
int64_t
moduloLong(int64_t b, int64_t a)
{
return a % b;
}
2008-07-05 20:21:13 +00:00
uint64_t
2007-12-09 22:45:43 +00:00
floatToDouble(int32_t a)
{
return doubleToBits(static_cast<double>(bitsToFloat(a)));
}
2008-07-05 20:21:13 +00:00
int32_t
2007-12-09 22:45:43 +00:00
floatToInt(int32_t a)
{
return static_cast<int32_t>(bitsToFloat(a));
}
2008-07-05 20:21:13 +00:00
int64_t
2007-12-09 22:45:43 +00:00
floatToLong(int32_t a)
{
return static_cast<int64_t>(bitsToFloat(a));
}
2008-07-05 20:21:13 +00:00
uint64_t
2007-12-09 22:45:43 +00:00
intToDouble(int32_t a)
{
return doubleToBits(static_cast<double>(a));
}
2008-07-05 20:21:13 +00:00
uint32_t
2007-12-09 22:45:43 +00:00
intToFloat(int32_t a)
{
return floatToBits(static_cast<float>(a));
}
2008-07-05 20:21:13 +00:00
uint64_t
2008-03-21 00:37:58 +00:00
longToDouble(int64_t a)
{
return doubleToBits(static_cast<double>(a));
}
2008-07-05 20:21:13 +00:00
uint32_t
2008-03-21 00:37:58 +00:00
longToFloat(int64_t a)
{
return floatToBits(static_cast<float>(a));
}
2008-07-05 20:21:13 +00:00
object
makeBlankObjectArray(MyThread* t, object class_, int32_t length)
2007-09-30 02:48:27 +00:00
{
if (length >= 0) {
return makeObjectArray(t, class_, length, true);
} else {
object message = makeString(t, "%d", length);
t->exception = makeNegativeArraySizeException(t, message);
unwind(t);
}
2007-09-30 02:48:27 +00:00
}
2008-07-05 20:21:13 +00:00
object
makeBlankArray(MyThread* t, object (*constructor)(Thread*, uintptr_t, bool),
2007-09-30 02:48:27 +00:00
int32_t length)
{
if (length >= 0) {
return constructor(t, length, true);
} else {
object message = makeString(t, "%d", length);
t->exception = makeNegativeArraySizeException(t, message);
unwind(t);
}
2007-09-30 02:48:27 +00:00
}
2008-07-05 20:21:13 +00:00
uintptr_t
2007-12-09 22:45:43 +00:00
lookUpAddress(int32_t key, uintptr_t* start, int32_t count,
uintptr_t default_)
{
2007-12-09 22:45:43 +00:00
int32_t bottom = 0;
int32_t top = count;
for (int32_t span = top - bottom; span; span = top - bottom) {
int32_t middle = bottom + (span / 2);
uintptr_t* p = start + (middle * 2);
int32_t k = *p;
if (key < k) {
top = middle;
} else if (key > k) {
bottom = middle + 1;
} else {
return p[1];
}
}
return default_;
2007-12-09 22:45:43 +00:00
}
2008-07-05 20:21:13 +00:00
void
2007-12-30 22:24:48 +00:00
setMaybeNull(MyThread* t, object o, unsigned offset, object value)
2007-12-09 22:45:43 +00:00
{
if (LIKELY(o)) {
2007-12-30 22:24:48 +00:00
set(t, o, offset, value);
} else {
t->exception = makeNullPointerException(t);
unwind(t);
}
}
2008-07-05 20:21:13 +00:00
void
2007-12-30 22:24:48 +00:00
acquireMonitorForObject(MyThread* t, object o)
{
if (LIKELY(o)) {
2007-12-30 22:24:48 +00:00
acquire(t, o);
} else {
t->exception = makeNullPointerException(t);
unwind(t);
}
2007-12-09 22:45:43 +00:00
}
2008-07-05 20:21:13 +00:00
void
2007-12-30 22:24:48 +00:00
releaseMonitorForObject(MyThread* t, object o)
2007-12-09 22:45:43 +00:00
{
if (LIKELY(o)) {
2007-12-30 22:24:48 +00:00
release(t, o);
} else {
t->exception = makeNullPointerException(t);
unwind(t);
}
2007-12-09 22:45:43 +00:00
}
2007-12-09 22:45:43 +00:00
object
makeMultidimensionalArray2(MyThread* t, object class_, uintptr_t* stack,
int32_t dimensions)
{
PROTECT(t, class_);
2007-12-09 22:45:43 +00:00
int32_t counts[dimensions];
for (int i = dimensions - 1; i >= 0; --i) {
counts[i] = stack[dimensions - i - 1];
if (UNLIKELY(counts[i] < 0)) {
object message = makeString(t, "%d", counts[i]);
t->exception = makeNegativeArraySizeException(t, message);
return 0;
}
}
2007-12-09 22:45:43 +00:00
object array = makeArray(t, counts[0], true);
setObjectClass(t, array, class_);
PROTECT(t, array);
2007-12-09 22:45:43 +00:00
populateMultiArray(t, array, counts, 0, dimensions);
2007-12-09 22:45:43 +00:00
return array;
}
2008-07-05 20:21:13 +00:00
object
makeMultidimensionalArray(MyThread* t, object class_, int32_t dimensions,
uintptr_t* stack)
{
2007-12-09 22:45:43 +00:00
object r = makeMultidimensionalArray2(t, class_, stack, dimensions);
if (UNLIKELY(t->exception)) {
unwind(t);
} else {
2007-12-09 22:45:43 +00:00
return r;
}
}
unsigned
traceSize(Thread* t)
{
class Counter: public Processor::StackVisitor {
public:
Counter(): count(0) { }
virtual bool visit(Processor::StackWalker*) {
++ count;
return true;
}
unsigned count;
} counter;
t->m->processor->walkStack(t, &counter);
return FixedSizeOfArray + (counter.count * ArrayElementSizeOfArray)
+ (counter.count * FixedSizeOfTraceElement);
}
2008-07-05 20:21:13 +00:00
void NO_RETURN
throwArrayIndexOutOfBounds(MyThread* t)
{
ensure(t, FixedSizeOfArrayIndexOutOfBoundsException + traceSize(t));
t->tracing = true;
t->exception = makeArrayIndexOutOfBoundsException(t, 0);
t->tracing = false;
2007-12-09 22:45:43 +00:00
unwind(t);
}
2008-07-05 20:21:13 +00:00
void NO_RETURN
2007-12-09 22:45:43 +00:00
throw_(MyThread* t, object o)
2007-10-09 17:15:40 +00:00
{
if (LIKELY(o)) {
2007-12-09 22:45:43 +00:00
t->exception = o;
} else {
t->exception = makeNullPointerException(t);
}
2007-12-09 22:45:43 +00:00
unwind(t);
}
2008-07-05 20:21:13 +00:00
void
checkCast(MyThread* t, object class_, object o)
{
if (UNLIKELY(o and not isAssignableFrom(t, class_, objectClass(t, o)))) {
object message = makeString
(t, "%s as %s",
&byteArrayBody(t, className(t, objectClass(t, o)), 0),
&byteArrayBody(t, className(t, class_), 0));
t->exception = makeClassCastException(t, message);
unwind(t);
}
}
2008-07-05 20:21:13 +00:00
void
2008-04-09 19:08:13 +00:00
gcIfNecessary(MyThread* t)
{
if (UNLIKELY(t->backupHeap)) {
collect(t, Heap::MinorCollection);
}
}
2008-02-11 17:21:41 +00:00
unsigned
resultSize(MyThread* t, unsigned code)
2007-12-09 22:45:43 +00:00
{
switch (code) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
2008-02-11 17:21:41 +00:00
case IntField:
return 4;
case ObjectField:
return BytesPerWord;
2007-09-25 23:53:11 +00:00
2007-12-09 22:45:43 +00:00
case LongField:
2008-02-11 17:21:41 +00:00
case DoubleField:
return 8;
2007-12-09 22:45:43 +00:00
case VoidField:
2008-02-11 17:21:41 +00:00
return 0;
2007-09-25 23:53:11 +00:00
2007-12-09 22:45:43 +00:00
default:
abort(t);
}
2007-12-09 22:45:43 +00:00
}
void
pushReturnValue(MyThread* t, Frame* frame, unsigned code,
Compiler::Operand* result)
{
switch (code) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField:
return frame->pushInt(result);
case ObjectField:
return frame->pushObject(result);
case LongField:
case DoubleField:
return frame->pushLong(result);
2007-09-25 23:53:11 +00:00
2007-12-09 22:45:43 +00:00
default:
abort(t);
}
2007-12-09 22:45:43 +00:00
}
bool
emptyMethod(MyThread* t, object method)
{
return ((methodFlags(t, method) & ACC_NATIVE) == 0)
and (codeLength(t, methodCode(t, method)) == 1)
and (codeBody(t, methodCode(t, method), 0) == return_);
}
2008-04-09 19:08:13 +00:00
object
defaultThunk(MyThread* t);
2008-04-09 19:08:13 +00:00
object
nativeThunk(MyThread* t);
2008-04-09 19:08:13 +00:00
object
aioobThunk(MyThread* t);
2008-04-09 19:08:13 +00:00
2007-12-09 22:45:43 +00:00
void
compileDirectInvoke(MyThread* t, Frame* frame, object target)
{
Compiler* c = frame->c;
unsigned rSize = resultSize(t, methodReturnCode(t, target));
Compiler::Operand* result = 0;
if (not emptyMethod(t, target)) {
if (methodFlags(t, target) & ACC_NATIVE) {
2008-07-05 20:21:13 +00:00
result = c->stackCall
(c->constant
(reinterpret_cast<intptr_t>
(&singletonBody(t, nativeThunk(t), 0))),
0,
frame->trace(target, false),
rSize,
2008-07-05 20:21:13 +00:00
methodParameterFootprint(t, target));
} else if (methodCompiled(t, target) == defaultThunk(t)) {
2008-07-05 20:21:13 +00:00
result = c->stackCall
(c->constant
(reinterpret_cast<intptr_t>
(&singletonBody(t, defaultThunk(t), 0))),
Compiler::Aligned,
frame->trace(target, false),
rSize,
2008-07-05 20:21:13 +00:00
methodParameterFootprint(t, target));
} else {
2008-07-05 20:21:13 +00:00
result = c->stackCall
(c->constant
(reinterpret_cast<intptr_t>
(&singletonBody(t, methodCompiled(t, target), 0))),
0,
frame->trace(0, false),
rSize,
2008-07-05 20:21:13 +00:00
methodParameterFootprint(t, target));
}
2008-04-09 19:08:13 +00:00
}
2007-09-25 23:53:11 +00:00
2007-12-09 22:45:43 +00:00
frame->pop(methodParameterFootprint(t, target));
2007-09-25 23:53:11 +00:00
if (rSize) {
pushReturnValue(t, frame, methodReturnCode(t, target), result);
2008-02-11 17:21:41 +00:00
}
2007-12-09 22:45:43 +00:00
}
void
handleMonitorEvent(MyThread* t, Frame* frame, intptr_t function)
{
Compiler* c = frame->c;
object method = frame->context->method;
if (methodFlags(t, method) & ACC_SYNCHRONIZED) {
2008-02-11 17:21:41 +00:00
Compiler::Operand* lock;
if (methodFlags(t, method) & ACC_STATIC) {
lock = frame->append(methodClass(t, method));
} else {
lock = c->memory
(c->base(), localOffset(t, savedTargetIndex(t, method), method));
}
2008-02-11 17:21:41 +00:00
c->call(c->constant(function),
0,
2008-02-11 17:21:41 +00:00
frame->trace(0, false),
0,
2, c->thread(), lock);
}
}
void
handleEntrance(MyThread* t, Frame* frame)
{
object method = frame->context->method;
if ((methodFlags(t, method) & (ACC_SYNCHRONIZED | ACC_STATIC))
== ACC_SYNCHRONIZED)
{
Compiler* c = frame->c;
// save 'this' pointer in case it is overwritten.
unsigned index = savedTargetIndex(t, method);
c->store(BytesPerWord,
c->memory(c->base(), localOffset(t, 0, method)),
2008-02-11 17:21:41 +00:00
c->memory(c->base(), localOffset(t, index, method)));
frame->set(index, Frame::Object);
}
handleMonitorEvent
(t, frame, getThunk(t, acquireMonitorForObjectThunk));
}
void
handleExit(MyThread* t, Frame* frame)
{
handleMonitorEvent
(t, frame, getThunk(t, releaseMonitorForObjectThunk));
}
2007-12-09 22:45:43 +00:00
void
2008-04-09 19:08:13 +00:00
compile(MyThread* t, Frame* initialFrame, unsigned ip,
bool exceptionHandler = false)
2007-12-09 22:45:43 +00:00
{
2008-02-11 17:21:41 +00:00
uint8_t stackMap
[codeMaxStack(t, methodCode(t, initialFrame->context->method))];
Frame myFrame(initialFrame, stackMap);
2007-12-09 22:45:43 +00:00
Frame* frame = &myFrame;
Compiler* c = frame->c;
Context* context = frame->context;
2007-09-25 23:53:11 +00:00
object code = methodCode(t, context->method);
2007-12-09 22:45:43 +00:00
PROTECT(t, code);
while (ip < codeLength(t, code)) {
2008-01-07 14:51:07 +00:00
if (context->visitTable[ip] ++) {
2007-12-09 22:45:43 +00:00
// we've already visited this part of the code
2008-04-20 05:23:08 +00:00
frame->visitLogicalIp(ip);
2007-12-09 22:45:43 +00:00
return;
2007-09-30 04:07:22 +00:00
}
2007-12-09 22:45:43 +00:00
frame->startLogicalIp(ip);
if (ip == 0) {
handleEntrance(t, frame);
} else if (exceptionHandler) {
2008-04-09 19:08:13 +00:00
exceptionHandler = false;
2008-04-19 07:03:59 +00:00
frame->pushObject();
2008-04-09 19:08:13 +00:00
2008-04-17 22:07:32 +00:00
c->call
(c->constant(getThunk(t, gcIfNecessaryThunk)),
0,
2008-04-09 19:08:13 +00:00
frame->trace(0, false),
2008-04-17 22:07:32 +00:00
0,
2008-04-09 19:08:13 +00:00
1, c->thread());
}
2008-01-07 14:51:07 +00:00
// fprintf(stderr, "ip: %d map: %ld\n", ip, *(frame->map));
2007-12-09 22:45:43 +00:00
unsigned instruction = codeBody(t, code, ip++);
2007-09-25 23:53:11 +00:00
2007-12-09 22:45:43 +00:00
switch (instruction) {
case aaload:
case baload:
case caload:
case daload:
case faload:
case iaload:
case laload:
case saload: {
2008-04-19 20:41:31 +00:00
Compiler::Operand* index = frame->popInt();
Compiler::Operand* array = frame->popObject();
if (CheckArrayBounds) {
c->checkBounds(array, ArrayLength, index, reinterpret_cast<intptr_t>
(&singletonValue(t, aioobThunk(t), 0)));
}
2007-09-25 23:53:11 +00:00
switch (instruction) {
case aaload:
frame->pushObject
(c->load
(BytesPerWord, c->memory(array, ArrayBody, index, BytesPerWord)));
break;
case faload:
case iaload:
frame->pushInt(c->load(4, c->memory(array, ArrayBody, index, 4)));
break;
case baload:
frame->pushInt(c->load(1, c->memory(array, ArrayBody, index, 1)));
break;
case caload:
frame->pushInt(c->loadz(2, c->memory(array, ArrayBody, index, 2)));
break;
case daload:
case laload:
frame->pushLong(c->load(8, c->memory(array, ArrayBody, index, 8)));
break;
case saload:
frame->pushInt(c->load(2, c->memory(array, ArrayBody, index, 2)));
break;
2007-12-09 22:45:43 +00:00
}
} break;
2007-12-09 22:45:43 +00:00
case aastore:
case bastore:
case castore:
case dastore:
case fastore:
case iastore:
case lastore:
case sastore: {
Compiler::Operand* value;
2007-12-09 22:45:43 +00:00
if (instruction == dastore or instruction == lastore) {
value = frame->popLong();
} else if (instruction == aastore) {
value = frame->popObject();
} else {
value = frame->popInt();
}
2007-09-30 02:48:27 +00:00
Compiler::Operand* index = frame->popInt();
Compiler::Operand* array = frame->popObject();
if (CheckArrayBounds) {
c->checkBounds(array, ArrayLength, index, reinterpret_cast<intptr_t>
(&singletonValue(t, aioobThunk(t), 0)));
}
switch (instruction) {
case aastore: {
c->call
(c->constant(getThunk(t, setMaybeNullThunk)),
0,
frame->trace(0, false),
0,
4, c->thread(), array,
c->add(4, c->constant(ArrayBody),
c->shl(4, c->constant(log(BytesPerWord)), index)),
value);
} break;
case fastore:
case iastore:
c->store(4, value, c->memory(array, ArrayBody, index, 4));
break;
case bastore:
c->store(1, value, c->memory(array, ArrayBody, index, 1));
break;
case castore:
case sastore:
c->store(2, value, c->memory(array, ArrayBody, index, 2));
break;
case dastore:
case lastore:
c->store(8, value, c->memory(array, ArrayBody, index, 8));
break;
2007-12-09 22:45:43 +00:00
}
} break;
2007-09-30 15:52:21 +00:00
2007-12-09 22:45:43 +00:00
case aconst_null:
frame->pushObject(c->constant(0));
break;
2007-09-25 23:53:11 +00:00
2007-12-09 22:45:43 +00:00
case aload:
frame->loadObject(codeBody(t, code, ip++));
break;
2007-12-09 22:45:43 +00:00
case aload_0:
frame->loadObject(0);
break;
2007-10-08 23:13:55 +00:00
2007-12-09 22:45:43 +00:00
case aload_1:
frame->loadObject(1);
break;
2007-12-09 22:45:43 +00:00
case aload_2:
frame->loadObject(2);
break;
2007-12-09 22:45:43 +00:00
case aload_3:
frame->loadObject(3);
break;
2007-12-09 22:45:43 +00:00
case anewarray: {
uint16_t index = codeReadInt16(t, code, ip);
object class_ = resolveClassInPool(t, codePool(t, code), index - 1);
if (UNLIKELY(t->exception)) return;
Compiler::Operand* length = frame->popInt();
2007-10-08 23:13:55 +00:00
2008-02-11 17:21:41 +00:00
frame->pushObject
(c->call
(c->constant(getThunk(t, makeBlankObjectArrayThunk)),
0,
2008-02-11 17:21:41 +00:00
frame->trace(0, false),
BytesPerWord,
3, c->thread(), frame->append(class_), length));
2007-12-09 22:45:43 +00:00
} break;
case areturn: {
handleExit(t, frame);
c->return_(BytesPerWord, frame->popObject());
} return;
case arraylength: {
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->load
(BytesPerWord, c->memory(frame->popObject(), ArrayLength, 0, 1)));
} break;
2007-10-04 03:19:39 +00:00
2007-12-09 22:45:43 +00:00
case astore:
frame->storeObjectOrAddress(codeBody(t, code, ip++));
2007-12-09 22:45:43 +00:00
break;
2007-10-10 21:34:04 +00:00
2007-12-09 22:45:43 +00:00
case astore_0:
frame->storeObjectOrAddress(0);
2007-12-09 22:45:43 +00:00
break;
2007-12-09 22:45:43 +00:00
case astore_1:
frame->storeObjectOrAddress(1);
2007-12-09 22:45:43 +00:00
break;
2007-10-10 21:34:04 +00:00
2007-12-09 22:45:43 +00:00
case astore_2:
frame->storeObjectOrAddress(2);
2007-12-09 22:45:43 +00:00
break;
2007-10-10 21:34:04 +00:00
2007-12-09 22:45:43 +00:00
case astore_3:
frame->storeObjectOrAddress(3);
2007-12-09 22:45:43 +00:00
break;
2007-10-10 21:34:04 +00:00
case athrow: {
2008-02-11 17:21:41 +00:00
c->call
(c->constant(getThunk(t, throw_Thunk)),
Compiler::NoReturn,
frame->trace(0, false),
2008-02-11 17:21:41 +00:00
0,
2, c->thread(), frame->popObject());
} return;
2007-12-09 22:45:43 +00:00
case bipush:
frame->pushInt
(c->constant(static_cast<int8_t>(codeBody(t, code, ip++))));
break;
2007-12-09 22:45:43 +00:00
case checkcast: {
uint16_t index = codeReadInt16(t, code, ip);
2007-12-09 22:45:43 +00:00
object class_ = resolveClassInPool(t, codePool(t, code), index - 1);
if (UNLIKELY(t->exception)) return;
Compiler::Operand* instance = c->peek(BytesPerWord, 0);
2008-02-11 17:21:41 +00:00
c->call
(c->constant(getThunk(t, checkCastThunk)),
0,
frame->trace(0, false),
2008-02-11 17:21:41 +00:00
0,
3, c->thread(), frame->append(class_), instance);
2007-12-09 22:45:43 +00:00
} break;
2007-10-10 21:34:04 +00:00
2007-12-09 22:45:43 +00:00
case d2f: {
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, doubleToFloatThunk)),
0, 0, 4, 2,
2008-05-23 00:08:41 +00:00
static_cast<Compiler::Operand*>(0), frame->popLong()));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case d2i: {
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, doubleToIntThunk)),
0, 0, 4, 2,
2008-05-23 00:08:41 +00:00
static_cast<Compiler::Operand*>(0), frame->popLong()));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case d2l: {
2008-02-11 17:21:41 +00:00
frame->pushLong
(c->call
(c->constant(getThunk(t, doubleToLongThunk)),
0, 0, 8, 2,
2008-05-23 00:08:41 +00:00
static_cast<Compiler::Operand*>(0), frame->popLong()));
2007-12-09 22:45:43 +00:00
} break;
2007-10-10 21:34:04 +00:00
2007-12-09 22:45:43 +00:00
case dadd: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
2008-02-11 17:21:41 +00:00
frame->pushLong
(c->call
(c->constant(getThunk(t, addDoubleThunk)),
0, 0, 8, 4,
static_cast<Compiler::Operand*>(0), a,
static_cast<Compiler::Operand*>(0), b));
2007-12-09 22:45:43 +00:00
} break;
2007-10-10 21:34:04 +00:00
2007-12-09 22:45:43 +00:00
case dcmpg: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, compareDoublesGThunk)),
0, 0, 4, 4,
static_cast<Compiler::Operand*>(0), a,
static_cast<Compiler::Operand*>(0), b));
2007-12-09 22:45:43 +00:00
} break;
2007-10-10 21:34:04 +00:00
2007-12-09 22:45:43 +00:00
case dcmpl: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, compareDoublesLThunk)),
0, 0, 4, 4,
static_cast<Compiler::Operand*>(0), a,
static_cast<Compiler::Operand*>(0), b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case dconst_0:
frame->pushLong(c->constant(doubleToBits(0.0)));
2007-12-09 22:45:43 +00:00
break;
case dconst_1:
frame->pushLong(c->constant(doubleToBits(1.0)));
2007-12-09 22:45:43 +00:00
break;
2007-12-09 22:45:43 +00:00
case ddiv: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
2008-02-11 17:21:41 +00:00
frame->pushLong
(c->call
(c->constant(getThunk(t, divideDoubleThunk)),
0, 0, 8, 4,
static_cast<Compiler::Operand*>(0), a,
static_cast<Compiler::Operand*>(0), b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case dmul: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
frame->pushLong
(c->call
(c->constant(getThunk(t, multiplyDoubleThunk)),
0, 0, 8, 4,
static_cast<Compiler::Operand*>(0), a,
static_cast<Compiler::Operand*>(0), b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case dneg: {
2008-02-11 17:21:41 +00:00
frame->pushLong
(c->call
(c->constant(getThunk(t, negateDoubleThunk)),
0, 0, 8, 2,
static_cast<Compiler::Operand*>(0), frame->popLong()));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case vm::drem: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
2008-02-11 17:21:41 +00:00
frame->pushLong
(c->call
(c->constant(getThunk(t, moduloDoubleThunk)),
0, 0, 8, 4,
static_cast<Compiler::Operand*>(0), a,
static_cast<Compiler::Operand*>(0), b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case dsub: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
2008-02-11 17:21:41 +00:00
frame->pushLong
(c->call
(c->constant(getThunk(t, subtractDoubleThunk)),
0, 0, 8, 4,
static_cast<Compiler::Operand*>(0), a,
static_cast<Compiler::Operand*>(0), b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case dup:
frame->dup();
break;
2007-12-09 22:45:43 +00:00
case dup_x1:
frame->dupX1();
break;
2007-12-09 22:45:43 +00:00
case dup_x2:
frame->dupX2();
break;
2007-12-09 22:45:43 +00:00
case dup2:
frame->dup2();
break;
2007-12-09 22:45:43 +00:00
case dup2_x1:
frame->dup2X1();
break;
2007-12-09 22:45:43 +00:00
case dup2_x2:
frame->dup2X2();
break;
2007-10-09 17:15:40 +00:00
2007-12-09 22:45:43 +00:00
case f2d: {
2008-02-11 17:21:41 +00:00
frame->pushLong
(c->call
(c->constant(getThunk(t, floatToDoubleThunk)),
0, 0, 8, 1, frame->popInt()));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case f2i: {
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, floatToIntThunk)),
0, 0, 4, 1, frame->popInt()));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case f2l: {
2008-02-11 17:21:41 +00:00
frame->pushLong
(c->call
(c->constant(getThunk(t, floatToLongThunk)),
0, 0, 8, 1, frame->popInt()));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case fadd: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, addFloatThunk)),
0, 0, 4, 2, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case fcmpg: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, compareFloatsGThunk)),
0, 0, 4, 2, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case fcmpl: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, compareFloatsLThunk)),
0, 0, 4, 2, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case fconst_0:
frame->pushInt(c->constant(floatToBits(0.0)));
break;
case fconst_1:
frame->pushInt(c->constant(floatToBits(1.0)));
break;
case fconst_2:
frame->pushInt(c->constant(floatToBits(2.0)));
break;
2007-12-09 22:45:43 +00:00
case fdiv: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, divideFloatThunk)),
0, 0, 4, 2, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case fmul: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, multiplyFloatThunk)),
0, 0, 4, 2, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case fneg: {
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, negateFloatThunk)),
0, 0, 4, 1, frame->popInt()));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case vm::frem: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, moduloFloatThunk)),
0, 0, 4, 2, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case fsub: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, subtractFloatThunk)),
0, 0, 4, 2, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case getfield:
case getstatic: {
uint16_t index = codeReadInt16(t, code, ip);
object field = resolveField(t, codePool(t, code), index - 1);
if (UNLIKELY(t->exception)) return;
2008-02-11 17:21:41 +00:00
Compiler::Operand* table;
2007-12-09 22:45:43 +00:00
if (instruction == getstatic) {
if ((classVmFlags(t, fieldClass(t, field)) & NeedInitFlag)
and (classVmFlags(t, fieldClass(t, field)) & InitFlag) == 0)
{
2008-03-16 19:38:43 +00:00
c->call
(c->constant(getThunk(t, tryInitClassThunk)),
0,
frame->trace(0, false),
2008-03-16 19:38:43 +00:00
0,
2, c->thread(), frame->append(fieldClass(t, field)));
}
2007-12-09 22:45:43 +00:00
table = frame->append(classStaticTable(t, fieldClass(t, field)));
} else {
table = frame->popObject();
}
2007-12-09 22:45:43 +00:00
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->load(1, c->memory(table, fieldOffset(t, field), 0, 1)));
2007-12-09 22:45:43 +00:00
break;
2007-12-09 22:45:43 +00:00
case CharField:
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->loadz(2, c->memory(table, fieldOffset(t, field), 0, 1)));
2007-12-09 22:45:43 +00:00
break;
2007-12-09 22:45:43 +00:00
case ShortField:
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->load(2, c->memory(table, fieldOffset(t, field), 0, 1)));
2007-12-09 22:45:43 +00:00
break;
2007-12-09 22:45:43 +00:00
case FloatField:
case IntField:
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->load(4, c->memory(table, fieldOffset(t, field), 0, 1)));
2007-12-09 22:45:43 +00:00
break;
2007-12-09 22:45:43 +00:00
case DoubleField:
case LongField:
2007-12-30 22:24:48 +00:00
frame->pushLong
(c->load(8, c->memory(table, fieldOffset(t, field), 0, 1)));
2007-12-09 22:45:43 +00:00
break;
2007-12-09 22:45:43 +00:00
case ObjectField:
2007-12-30 22:24:48 +00:00
frame->pushObject
(c->load
(BytesPerWord, c->memory(table, fieldOffset(t, field), 0, 1)));
2007-12-09 22:45:43 +00:00
break;
2007-12-09 22:45:43 +00:00
default:
abort(t);
}
} break;
2007-12-09 22:45:43 +00:00
case goto_: {
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
assert(t, newIp < codeLength(t, code));
2007-12-16 00:24:15 +00:00
c->jmp(frame->machineIp(newIp));
2007-12-09 22:45:43 +00:00
ip = newIp;
} break;
2007-12-09 22:45:43 +00:00
case goto_w: {
uint32_t newIp = (ip - 5) + codeReadInt32(t, code, ip);
assert(t, newIp < codeLength(t, code));
2007-12-16 00:24:15 +00:00
c->jmp(frame->machineIp(newIp));
2007-12-09 22:45:43 +00:00
ip = newIp;
} break;
2007-12-09 22:45:43 +00:00
case i2b: {
frame->pushInt(c->load(1, frame->popInt()));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case i2c: {
frame->pushInt(c->loadz(2, frame->popInt()));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case i2d: {
2008-02-11 17:21:41 +00:00
frame->pushLong
(c->call
(c->constant(getThunk(t, intToDoubleThunk)),
0, 0, 8, 1, frame->popInt()));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case i2f: {
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, intToFloatThunk)),
0, 0, 4, 1, frame->popInt()));
2007-12-09 22:45:43 +00:00
} break;
case i2l:
2008-02-11 17:21:41 +00:00
frame->pushLong(c->load4To8(frame->popInt()));
break;
2007-10-04 03:19:39 +00:00
2007-12-09 22:45:43 +00:00
case i2s: {
frame->pushInt(c->load(2, frame->popInt()));
2007-12-09 22:45:43 +00:00
} break;
case iadd: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
frame->pushInt(c->add(4, a, b));
2007-12-09 22:45:43 +00:00
} break;
case iand: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
frame->pushInt(c->and_(4, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-10-04 00:41:54 +00:00
2007-12-09 22:45:43 +00:00
case iconst_m1:
frame->pushInt(c->constant(-1));
break;
2007-10-04 00:41:54 +00:00
2007-12-09 22:45:43 +00:00
case iconst_0:
frame->pushInt(c->constant(0));
break;
2007-10-04 00:41:54 +00:00
2007-12-09 22:45:43 +00:00
case iconst_1:
frame->pushInt(c->constant(1));
break;
2007-12-09 22:45:43 +00:00
case iconst_2:
frame->pushInt(c->constant(2));
break;
2007-12-09 22:45:43 +00:00
case iconst_3:
frame->pushInt(c->constant(3));
break;
2007-09-30 02:48:27 +00:00
2007-12-09 22:45:43 +00:00
case iconst_4:
frame->pushInt(c->constant(4));
break;
2007-09-30 02:48:27 +00:00
2007-12-09 22:45:43 +00:00
case iconst_5:
frame->pushInt(c->constant(5));
break;
2007-12-09 22:45:43 +00:00
case idiv: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
frame->pushInt(c->div(4, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case if_acmpeq:
case if_acmpne: {
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
assert(t, newIp < codeLength(t, code));
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popObject();
Compiler::Operand* b = frame->popObject();
Compiler::Operand* target = frame->machineIp(newIp);
c->cmp(BytesPerWord, a, b);
2007-12-09 22:45:43 +00:00
if (instruction == if_acmpeq) {
c->je(target);
} else {
c->jne(target);
}
compile(t, frame, newIp);
if (UNLIKELY(t->exception)) return;
} break;
2007-12-09 22:45:43 +00:00
case if_icmpeq:
case if_icmpne:
case if_icmpgt:
case if_icmpge:
case if_icmplt:
case if_icmple: {
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
assert(t, newIp < codeLength(t, code));
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
Compiler::Operand* target = frame->machineIp(newIp);
c->cmp(4, a, b);
2007-12-09 22:45:43 +00:00
switch (instruction) {
case if_icmpeq:
c->je(target);
break;
case if_icmpne:
c->jne(target);
break;
case if_icmpgt:
c->jg(target);
break;
case if_icmpge:
c->jge(target);
break;
case if_icmplt:
c->jl(target);
break;
case if_icmple:
c->jle(target);
break;
}
compile(t, frame, newIp);
if (UNLIKELY(t->exception)) return;
} break;
2007-10-03 00:22:48 +00:00
2007-12-09 22:45:43 +00:00
case ifeq:
case ifne:
case ifgt:
case ifge:
case iflt:
case ifle: {
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
assert(t, newIp < codeLength(t, code));
2007-10-03 00:22:48 +00:00
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* target = frame->machineIp(newIp);
c->cmp(4, c->constant(0), a);
2007-12-09 22:45:43 +00:00
switch (instruction) {
case ifeq:
c->je(target);
break;
case ifne:
c->jne(target);
break;
case ifgt:
c->jg(target);
break;
case ifge:
c->jge(target);
break;
case iflt:
c->jl(target);
break;
case ifle:
c->jle(target);
break;
}
2007-12-09 22:45:43 +00:00
compile(t, frame, newIp);
if (UNLIKELY(t->exception)) return;
} break;
2007-12-09 22:45:43 +00:00
case ifnull:
case ifnonnull: {
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
assert(t, newIp < codeLength(t, code));
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popObject();
Compiler::Operand* target = frame->machineIp(newIp);
2007-09-30 02:48:27 +00:00
c->cmp(BytesPerWord, c->constant(0), a);
2007-12-09 22:45:43 +00:00
if (instruction == ifnull) {
c->je(target);
} else {
c->jne(target);
}
compile(t, frame, newIp);
if (UNLIKELY(t->exception)) return;
} break;
2007-09-29 21:08:29 +00:00
2007-12-09 22:45:43 +00:00
case iinc: {
uint8_t index = codeBody(t, code, ip++);
int8_t count = codeBody(t, code, ip++);
2007-09-29 21:08:29 +00:00
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = c->memory
(c->base(), localOffset(t, index, context->method));
c->storeLocal(4, c->add(4, c->constant(count), a), index);
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case iload:
case fload:
frame->loadInt(codeBody(t, code, ip++));
break;
2007-12-09 22:45:43 +00:00
case iload_0:
case fload_0:
frame->loadInt(0);
break;
2007-12-09 22:45:43 +00:00
case iload_1:
case fload_1:
frame->loadInt(1);
break;
2007-12-09 22:45:43 +00:00
case iload_2:
case fload_2:
frame->loadInt(2);
break;
2007-10-03 00:22:48 +00:00
2007-12-09 22:45:43 +00:00
case iload_3:
case fload_3:
frame->loadInt(3);
break;
2007-10-03 00:22:48 +00:00
2007-12-09 22:45:43 +00:00
case imul: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
frame->pushInt(c->mul(4, a, b));
2007-12-09 22:45:43 +00:00
} break;
case ineg: {
frame->pushInt(c->neg(4, frame->popInt()));
} break;
2007-12-09 22:45:43 +00:00
case instanceof: {
uint16_t index = codeReadInt16(t, code, ip);
2007-09-30 04:07:22 +00:00
2007-12-09 22:45:43 +00:00
object class_ = resolveClassInPool(t, codePool(t, code), index - 1);
if (UNLIKELY(t->exception)) return;
2007-09-30 04:07:22 +00:00
2008-02-11 17:21:41 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, instanceOfThunk)),
0, 0, 4,
2008-02-11 17:21:41 +00:00
3, c->thread(), frame->append(class_), frame->popObject()));
2007-12-09 22:45:43 +00:00
} break;
2007-09-30 02:48:27 +00:00
2007-12-09 22:45:43 +00:00
case invokeinterface: {
uint16_t index = codeReadInt16(t, code, ip);
ip += 2;
2007-09-30 02:48:27 +00:00
2007-12-09 22:45:43 +00:00
object target = resolveMethod(t, codePool(t, code), index - 1);
if (UNLIKELY(t->exception)) return;
2007-09-30 02:48:27 +00:00
assert(t, (methodFlags(t, target) & ACC_STATIC) == 0);
2007-12-09 22:45:43 +00:00
unsigned parameterFootprint = methodParameterFootprint(t, target);
2007-09-30 02:48:27 +00:00
2007-12-09 22:45:43 +00:00
unsigned instance = parameterFootprint - 1;
unsigned rSize = resultSize(t, methodReturnCode(t, target));
2008-07-05 20:21:13 +00:00
Compiler::Operand* result = c->stackCall
2008-02-11 17:21:41 +00:00
(c->call
(c->constant
(getThunk(t, findInterfaceMethodFromInstanceThunk)),
0,
frame->trace(0, false),
2008-02-11 17:21:41 +00:00
BytesPerWord,
3, c->thread(), frame->append(target),
c->peek(BytesPerWord, instance)),
2008-02-11 17:21:41 +00:00
0,
frame->trace(target, true),
rSize,
2008-07-05 20:21:13 +00:00
parameterFootprint);
2007-09-30 15:52:21 +00:00
2007-12-09 22:45:43 +00:00
frame->pop(parameterFootprint);
if (rSize) {
pushReturnValue(t, frame, methodReturnCode(t, target), result);
2008-02-11 17:21:41 +00:00
}
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case invokespecial: {
uint16_t index = codeReadInt16(t, code, ip);
2007-12-09 22:45:43 +00:00
object target = resolveMethod(t, codePool(t, code), index - 1);
if (UNLIKELY(t->exception)) return;
object class_ = methodClass(t, context->method);
2007-12-09 22:45:43 +00:00
if (isSpecialMethod(t, target, class_)) {
target = findMethod(t, target, classSuper(t, class_));
}
assert(t, (methodFlags(t, target) & ACC_STATIC) == 0);
2007-12-09 22:45:43 +00:00
compileDirectInvoke(t, frame, target);
} break;
2007-12-09 22:45:43 +00:00
case invokestatic: {
uint16_t index = codeReadInt16(t, code, ip);
2007-09-30 02:48:27 +00:00
2007-12-09 22:45:43 +00:00
object target = resolveMethod(t, codePool(t, code), index - 1);
if (UNLIKELY(t->exception)) return;
2007-09-29 21:08:29 +00:00
assert(t, methodFlags(t, target) & ACC_STATIC);
2007-12-09 22:45:43 +00:00
compileDirectInvoke(t, frame, target);
} break;
2007-09-29 21:08:29 +00:00
2007-12-09 22:45:43 +00:00
case invokevirtual: {
uint16_t index = codeReadInt16(t, code, ip);
2007-09-29 21:08:29 +00:00
2007-12-09 22:45:43 +00:00
object target = resolveMethod(t, codePool(t, code), index - 1);
if (UNLIKELY(t->exception)) return;
2007-09-29 21:08:29 +00:00
assert(t, (methodFlags(t, target) & ACC_STATIC) == 0);
2007-12-09 22:45:43 +00:00
unsigned parameterFootprint = methodParameterFootprint(t, target);
2007-12-09 22:45:43 +00:00
unsigned offset = ClassVtable + (methodOffset(t, target) * BytesPerWord);
2007-09-29 21:08:29 +00:00
Compiler::Operand* instance = c->peek
(BytesPerWord, parameterFootprint - 1);
2007-09-29 21:08:29 +00:00
unsigned rSize = resultSize(t, methodReturnCode(t, target));
2008-07-05 20:21:13 +00:00
Compiler::Operand* result = c->stackCall
2008-02-11 17:21:41 +00:00
(c->memory
(c->and_
(BytesPerWord, c->constant(PointerMask),
c->memory(instance, 0, 0, 1)), offset, 0, 1),
2008-02-11 17:21:41 +00:00
0,
frame->trace(target, true),
rSize,
2008-07-05 20:21:13 +00:00
parameterFootprint);
2007-12-09 22:45:43 +00:00
frame->pop(parameterFootprint);
if (rSize) {
pushReturnValue(t, frame, methodReturnCode(t, target), result);
2008-02-11 17:21:41 +00:00
}
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case ior: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
frame->pushInt(c->or_(4, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case irem: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
frame->pushInt(c->rem(4, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case ireturn:
case freturn: {
handleExit(t, frame);
c->return_(4, frame->popInt());
} return;
2007-12-09 22:45:43 +00:00
case ishl: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
frame->pushInt(c->shl(4, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case ishr: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
frame->pushInt(c->shr(4, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case istore:
case fstore:
frame->storeInt(codeBody(t, code, ip++));
break;
2007-12-09 22:45:43 +00:00
case istore_0:
case fstore_0:
frame->storeInt(0);
break;
2007-12-09 22:45:43 +00:00
case istore_1:
case fstore_1:
frame->storeInt(1);
break;
2007-12-09 22:45:43 +00:00
case istore_2:
case fstore_2:
frame->storeInt(2);
break;
2007-12-09 22:45:43 +00:00
case istore_3:
case fstore_3:
frame->storeInt(3);
break;
2007-12-09 22:45:43 +00:00
case isub: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
frame->pushInt(c->sub(4, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case iushr: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
frame->pushInt(c->ushr(4, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case ixor: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popInt();
Compiler::Operand* b = frame->popInt();
frame->pushInt(c->xor_(4, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case jsr:
case jsr_w: {
uint32_t newIp;
if (instruction == jsr) {
newIp = (ip - 3) + codeReadInt16(t, code, ip);
} else {
newIp = (ip - 5) + codeReadInt32(t, code, ip);
}
assert(t, newIp < codeLength(t, code));
c->saveStack();
frame->pushAddress(frame->machineIp(ip));
c->jmp(frame->machineIp(newIp));
// NB: we assume that the stack will look the same on return
// from the subroutine as at call time.
compile(t, frame, newIp);
if (UNLIKELY(t->exception)) return;
frame->pop(1);
2007-12-16 21:30:19 +00:00
} break;
2008-03-21 00:37:58 +00:00
case l2d: {
2008-04-17 22:07:32 +00:00
frame->pushLong
(c->call
(c->constant(getThunk(t, longToDoubleThunk)),
0, 0, 8, 2,
2008-05-23 00:08:41 +00:00
static_cast<Compiler::Operand*>(0), frame->popLong()));
2008-03-21 00:37:58 +00:00
} break;
case l2f: {
2008-04-17 22:07:32 +00:00
frame->pushInt
(c->call
(c->constant(getThunk(t, longToFloatThunk)),
0, 0, 4, 2,
2008-05-23 00:08:41 +00:00
static_cast<Compiler::Operand*>(0), frame->popLong()));
2008-03-21 00:37:58 +00:00
} break;
case l2i:
frame->pushInt(c->load(4, frame->popLong()));
break;
2007-12-09 22:45:43 +00:00
case ladd: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
frame->pushLong(c->add(8, a, b));
2007-12-09 22:45:43 +00:00
} break;
case land: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
frame->pushLong(c->and_(8, a, b));
} break;
2007-12-09 22:45:43 +00:00
case lcmp: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
frame->pushInt(c->load(4, c->lcmp(a, b)));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case lconst_0:
frame->pushLong(c->constant(0));
2007-12-09 22:45:43 +00:00
break;
2007-12-09 22:45:43 +00:00
case lconst_1:
frame->pushLong(c->constant(1));
2007-12-09 22:45:43 +00:00
break;
2007-09-30 02:48:27 +00:00
2007-12-09 22:45:43 +00:00
case ldc:
case ldc_w: {
uint16_t index;
2007-09-30 02:48:27 +00:00
2007-12-09 22:45:43 +00:00
if (instruction == ldc) {
index = codeBody(t, code, ip++);
} else {
index = codeReadInt16(t, code, ip);
}
2007-09-30 15:52:21 +00:00
2007-12-09 22:45:43 +00:00
object pool = codePool(t, code);
2007-09-30 15:52:21 +00:00
2007-12-09 22:45:43 +00:00
if (singletonIsObject(t, pool, index - 1)) {
object v = singletonObject(t, pool, index - 1);
if (objectClass(t, v)
== arrayBody(t, t->m->types, Machine::ByteArrayType))
{
object class_ = resolveClassInPool(t, pool, index - 1);
if (UNLIKELY(t->exception)) return;
2007-09-30 15:52:21 +00:00
2007-12-09 22:45:43 +00:00
frame->pushObject(frame->append(class_));
} else {
2007-12-09 22:45:43 +00:00
frame->pushObject(frame->append(v));
}
2007-12-09 22:45:43 +00:00
} else {
frame->pushInt(c->constant(singletonValue(t, pool, index - 1)));
}
} break;
2007-10-04 22:41:19 +00:00
2007-12-09 22:45:43 +00:00
case ldc2_w: {
uint16_t index = codeReadInt16(t, code, ip);
2007-12-09 22:45:43 +00:00
object pool = codePool(t, code);
2007-12-09 22:45:43 +00:00
uint64_t v;
memcpy(&v, &singletonValue(t, pool, index - 1), 8);
frame->pushLong(c->constant(v));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case ldiv_: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
frame->pushLong(c->div(8, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case lload:
case dload:
frame->loadLong(codeBody(t, code, ip++));
break;
2007-12-09 22:45:43 +00:00
case lload_0:
case dload_0:
frame->loadLong(0);
break;
2007-12-09 22:45:43 +00:00
case lload_1:
case dload_1:
frame->loadLong(1);
break;
2007-12-09 22:45:43 +00:00
case lload_2:
case dload_2:
frame->loadLong(2);
break;
2007-12-09 22:45:43 +00:00
case lload_3:
case dload_3:
frame->loadLong(3);
break;
2007-12-09 22:45:43 +00:00
case lmul: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
frame->pushLong(c->mul(8, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case lneg:
frame->pushLong(c->neg(8, frame->popLong()));
2007-12-09 22:45:43 +00:00
break;
2007-12-09 22:45:43 +00:00
case lookupswitch: {
int32_t base = ip - 1;
2007-12-09 22:45:43 +00:00
ip = (ip + 3) & ~3; // pad to four byte boundary
2008-02-11 17:21:41 +00:00
Compiler::Operand* key = frame->popInt();
2007-12-09 22:45:43 +00:00
uint32_t defaultIp = base + codeReadInt32(t, code, ip);
assert(t, defaultIp < codeLength(t, code));
2008-02-11 17:21:41 +00:00
Compiler::Operand* default_ = c->address
2007-12-16 00:24:15 +00:00
(c->poolAppendPromise(c->machineIp(defaultIp)));
2007-12-09 22:45:43 +00:00
int32_t pairCount = codeReadInt32(t, code, ip);
2008-02-11 17:21:41 +00:00
Compiler::Operand* start = 0;
2007-12-16 00:24:15 +00:00
uint32_t ipTable[pairCount];
2007-12-09 22:45:43 +00:00
for (int32_t i = 0; i < pairCount; ++i) {
unsigned index = ip + (i * 8);
int32_t key = codeReadInt32(t, code, index);
uint32_t newIp = base + codeReadInt32(t, code, index);
assert(t, newIp < codeLength(t, code));
2007-12-16 00:24:15 +00:00
ipTable[i] = newIp;
2007-12-16 00:24:15 +00:00
Promise* p = c->poolAppend(key);
2007-12-09 22:45:43 +00:00
if (i == 0) {
2007-12-16 00:24:15 +00:00
start = c->promiseConstant(p);
2007-12-09 22:45:43 +00:00
}
2007-12-16 00:24:15 +00:00
c->poolAppendPromise(c->machineIp(newIp));
2007-12-09 22:45:43 +00:00
}
2007-12-16 00:24:15 +00:00
assert(t, start);
2008-02-11 17:21:41 +00:00
c->jmp
(c->call
(c->constant(getThunk(t, lookUpAddressThunk)),
0, 0, BytesPerWord,
2008-02-11 17:21:41 +00:00
4, key, start, c->constant(pairCount), default_));
2007-12-16 00:24:15 +00:00
for (int32_t i = 0; i < pairCount; ++i) {
compile(t, frame, ipTable[i]);
if (UNLIKELY(t->exception)) return;
}
2008-01-07 14:51:07 +00:00
ip = defaultIp;
} break;
2007-12-09 22:45:43 +00:00
case lor: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
frame->pushLong(c->or_(8, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case lrem: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
frame->pushLong(c->rem(8, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case lreturn:
case dreturn: {
handleExit(t, frame);
c->return_(8, frame->popLong());
} return;
2007-12-09 22:45:43 +00:00
case lshl: {
Compiler::Operand* a = frame->popInt();
2008-02-11 17:21:41 +00:00
Compiler::Operand* b = frame->popLong();
frame->pushLong(c->shl(8, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case lshr: {
Compiler::Operand* a = frame->popInt();
2008-02-11 17:21:41 +00:00
Compiler::Operand* b = frame->popLong();
frame->pushLong(c->shr(8, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case lstore:
case dstore:
frame->storeLong(codeBody(t, code, ip++));
break;
2007-12-09 22:45:43 +00:00
case lstore_0:
case dstore_0:
frame->storeLong(0);
break;
2007-12-09 22:45:43 +00:00
case lstore_1:
case dstore_1:
frame->storeLong(1);
break;
case lstore_2:
case dstore_2:
frame->storeLong(2);
break;
case lstore_3:
case dstore_3:
frame->storeLong(3);
break;
2007-12-09 22:45:43 +00:00
case lsub: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
frame->pushLong(c->sub(8, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case lushr: {
Compiler::Operand* a = frame->popInt();
2008-02-11 17:21:41 +00:00
Compiler::Operand* b = frame->popLong();
frame->pushLong(c->ushr(8, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case lxor: {
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = frame->popLong();
Compiler::Operand* b = frame->popLong();
frame->pushLong(c->xor_(8, a, b));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case monitorenter: {
2008-02-11 17:21:41 +00:00
c->call
(c->constant(getThunk(t, acquireMonitorForObjectThunk)),
0,
2008-05-06 21:13:02 +00:00
frame->trace(0, false), 0, 2, c->thread(), frame->popObject());
2007-12-09 22:45:43 +00:00
} break;
2007-09-29 21:08:29 +00:00
2007-12-09 22:45:43 +00:00
case monitorexit: {
2008-02-11 17:21:41 +00:00
c->call
(c->constant(getThunk(t, releaseMonitorForObjectThunk)),
0,
2008-05-06 21:13:02 +00:00
frame->trace(0, false), 0, 2, c->thread(), frame->popObject());
2007-12-09 22:45:43 +00:00
} break;
2007-09-29 21:08:29 +00:00
2007-12-09 22:45:43 +00:00
case multianewarray: {
uint16_t index = codeReadInt16(t, code, ip);
uint8_t dimensions = codeBody(t, code, ip++);
2007-12-09 22:45:43 +00:00
object class_ = resolveClassInPool(t, codePool(t, code), index - 1);
if (UNLIKELY(t->exception)) return;
PROTECT(t, class_);
2008-02-11 17:21:41 +00:00
Compiler::Operand* result = c->call
(c->constant(getThunk(t, makeMultidimensionalArrayThunk)),
0,
frame->trace(0, false),
2008-02-11 17:21:41 +00:00
BytesPerWord,
4, c->thread(), frame->append(class_), c->constant(dimensions),
c->stack());
2007-12-09 22:45:43 +00:00
frame->pop(dimensions);
frame->pushObject(result);
} break;
2007-10-12 00:30:46 +00:00
2007-12-09 22:45:43 +00:00
case new_: {
uint16_t index = codeReadInt16(t, code, ip);
object class_ = resolveClassInPool(t, codePool(t, code), index - 1);
if (UNLIKELY(t->exception)) return;
if (classVmFlags(t, class_) & WeakReferenceFlag) {
2008-02-11 17:21:41 +00:00
frame->pushObject
(c->call
(c->constant(getThunk(t, makeNewWeakReferenceThunk)),
0,
2008-02-11 17:21:41 +00:00
frame->trace(0, false),
BytesPerWord,
2, c->thread(), frame->append(class_)));
2007-12-09 22:45:43 +00:00
} else {
2008-02-11 17:21:41 +00:00
frame->pushObject
(c->call
(c->constant(getThunk(t, makeNewThunk)),
0,
2008-02-11 17:21:41 +00:00
frame->trace(0, false),
BytesPerWord,
2, c->thread(), frame->append(class_)));
2007-12-09 22:45:43 +00:00
}
} break;
2007-12-09 22:45:43 +00:00
case newarray: {
uint8_t type = codeBody(t, code, ip++);
Compiler::Operand* length = frame->popInt();
2007-12-09 22:45:43 +00:00
object (*constructor)(Thread*, uintptr_t, bool);
switch (type) {
case T_BOOLEAN:
constructor = makeBooleanArray;
break;
2007-12-09 22:45:43 +00:00
case T_CHAR:
constructor = makeCharArray;
break;
2007-12-09 22:45:43 +00:00
case T_FLOAT:
constructor = makeFloatArray;
break;
2007-12-09 22:45:43 +00:00
case T_DOUBLE:
constructor = makeDoubleArray;
break;
2007-12-09 22:45:43 +00:00
case T_BYTE:
constructor = makeByteArray;
break;
2007-12-09 22:45:43 +00:00
case T_SHORT:
constructor = makeShortArray;
break;
2007-12-09 22:45:43 +00:00
case T_INT:
constructor = makeIntArray;
break;
2007-12-09 22:45:43 +00:00
case T_LONG:
constructor = makeLongArray;
break;
2007-12-09 22:45:43 +00:00
default: abort(t);
}
2008-02-11 17:21:41 +00:00
frame->pushObject
(c->call
(c->constant(getThunk(t, makeBlankArrayThunk)),
0,
2008-02-11 17:21:41 +00:00
frame->trace(0, false),
BytesPerWord,
3, c->thread(), c->constant(reinterpret_cast<intptr_t>(constructor)),
2008-02-11 17:21:41 +00:00
length));
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case nop: break;
2007-12-09 22:45:43 +00:00
case pop_:
frame->pop(1);
break;
2007-12-09 22:45:43 +00:00
case pop2:
frame->pop(2);
break;
2007-12-09 22:45:43 +00:00
case putfield:
case putstatic: {
uint16_t index = codeReadInt16(t, code, ip);
object field = resolveField(t, codePool(t, code), index - 1);
if (UNLIKELY(t->exception)) return;
object staticTable = 0;
2007-12-09 22:45:43 +00:00
if (instruction == putstatic) {
if ((classVmFlags(t, fieldClass(t, field)) & NeedInitFlag)
and (classVmFlags(t, fieldClass(t, field)) & InitFlag) == 0)
{
2008-03-16 19:38:43 +00:00
c->call
(c->constant(getThunk(t, tryInitClassThunk)),
0,
frame->trace(0, false),
2008-03-16 19:38:43 +00:00
0,
2, c->thread(), frame->append(fieldClass(t, field)));
}
2007-12-09 22:45:43 +00:00
staticTable = classStaticTable(t, fieldClass(t, field));
}
2007-10-12 22:06:33 +00:00
2008-02-11 17:21:41 +00:00
Compiler::Operand* value;
2007-12-09 22:45:43 +00:00
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField: {
value = frame->popInt();
} break;
2007-12-09 22:45:43 +00:00
case DoubleField:
case LongField: {
value = frame->popLong();
} break;
2007-12-09 22:45:43 +00:00
case ObjectField: {
value = frame->popObject();
} break;
2007-12-09 22:45:43 +00:00
default: abort(t);
}
2008-02-11 17:21:41 +00:00
Compiler::Operand* table;
2007-12-09 22:45:43 +00:00
if (instruction == putstatic) {
table = frame->append(staticTable);
} else {
table = frame->popObject();
}
2007-12-09 22:45:43 +00:00
switch (fieldCode(t, field)) {
case ByteField:
case BooleanField:
c->store(1, value, c->memory(table, fieldOffset(t, field), 0, 1));
break;
2007-12-09 22:45:43 +00:00
case CharField:
case ShortField:
c->store(2, value, c->memory(table, fieldOffset(t, field), 0, 1));
break;
2007-12-09 22:45:43 +00:00
case FloatField:
case IntField:
c->store(4, value, c->memory(table, fieldOffset(t, field), 0, 1));
break;
2007-12-09 22:45:43 +00:00
case DoubleField:
case LongField:
c->store(8, value, c->memory(table, fieldOffset(t, field), 0, 1));
break;
2007-12-09 22:45:43 +00:00
case ObjectField:
if (instruction == putfield) {
2008-02-11 17:21:41 +00:00
c->call
(c->constant(getThunk(t, setMaybeNullThunk)),
0,
frame->trace(0, false),
2008-02-11 17:21:41 +00:00
0,
2007-12-30 22:24:48 +00:00
4, c->thread(), table, c->constant(fieldOffset(t, field)), value);
} else {
2008-02-11 17:21:41 +00:00
c->call
(c->constant(getThunk(t, setThunk)),
0, 0, 0,
2007-12-30 22:24:48 +00:00
4, c->thread(), table, c->constant(fieldOffset(t, field)), value);
}
break;
2007-12-09 22:45:43 +00:00
default: abort(t);
}
} break;
case ret:
c->jmp
(c->memory
(c->base(), localOffset
(t, codeBody(t, code, ip), context->method)));
return;
2007-12-09 22:45:43 +00:00
case return_:
handleExit(t, frame);
c->return_(0, 0);
2007-12-09 22:45:43 +00:00
return;
2007-12-09 22:45:43 +00:00
case sipush:
frame->pushInt
(c->constant(static_cast<int16_t>(codeReadInt16(t, code, ip))));
break;
2007-12-09 22:45:43 +00:00
case swap:
frame->swap();
break;
2007-12-09 22:45:43 +00:00
case tableswitch: {
int32_t base = ip - 1;
2007-12-09 22:45:43 +00:00
ip = (ip + 3) & ~3; // pad to four byte boundary
2007-09-30 02:48:27 +00:00
2007-12-09 22:45:43 +00:00
uint32_t defaultIp = base + codeReadInt32(t, code, ip);
assert(t, defaultIp < codeLength(t, code));
int32_t bottom = codeReadInt32(t, code, ip);
int32_t top = codeReadInt32(t, code, ip);
2008-02-11 17:21:41 +00:00
Compiler::Operand* start = 0;
2007-12-16 00:24:15 +00:00
uint32_t ipTable[top - bottom + 1];
for (int32_t i = 0; i < top - bottom + 1; ++i) {
2007-12-09 22:45:43 +00:00
unsigned index = ip + (i * 4);
uint32_t newIp = base + codeReadInt32(t, code, index);
assert(t, newIp < codeLength(t, code));
2007-12-16 00:24:15 +00:00
ipTable[i] = newIp;
Promise* p = c->poolAppendPromise(c->machineIp(newIp));
2007-12-09 22:45:43 +00:00
if (i == 0) {
2007-12-16 00:24:15 +00:00
start = c->promiseConstant(p);
}
2007-12-09 22:45:43 +00:00
}
2007-12-16 00:24:15 +00:00
assert(t, start);
2008-02-11 17:21:41 +00:00
Compiler::Operand* defaultCase = c->label();
Compiler::Operand* key = frame->popInt();
2007-12-09 22:45:43 +00:00
c->cmp(4, c->constant(bottom), key);
2007-12-09 22:45:43 +00:00
c->jl(defaultCase);
2007-10-04 22:41:19 +00:00
c->cmp(4, c->constant(top), key);
2007-12-09 22:45:43 +00:00
c->jg(defaultCase);
2007-10-04 22:41:19 +00:00
2008-04-20 19:35:36 +00:00
c->jmp(c->memory(start, 0, c->sub(4, c->constant(bottom), key),
BytesPerWord));
2007-12-09 22:45:43 +00:00
c->mark(defaultCase);
2007-12-16 00:24:15 +00:00
c->jmp(frame->machineIp(defaultIp));
2007-12-16 00:24:15 +00:00
for (int32_t i = 0; i < top - bottom + 1; ++i) {
compile(t, frame, ipTable[i]);
if (UNLIKELY(t->exception)) return;
}
2008-01-07 14:51:07 +00:00
ip = defaultIp;
} break;
2007-12-09 22:45:43 +00:00
case wide: {
switch (codeBody(t, code, ip++)) {
case aload: {
frame->loadObject(codeReadInt16(t, code, ip));
2007-10-04 22:41:19 +00:00
} break;
2007-12-09 22:45:43 +00:00
case astore: {
frame->storeObject(codeReadInt16(t, code, ip));
} break;
2007-10-04 22:41:19 +00:00
2007-12-09 22:45:43 +00:00
case iinc: {
uint16_t index = codeReadInt16(t, code, ip);
uint16_t count = codeReadInt16(t, code, ip);
2007-10-04 22:41:19 +00:00
2008-02-11 17:21:41 +00:00
Compiler::Operand* a = c->memory
(c->base(), localOffset(t, index, context->method));
c->storeLocal(4, c->add(4, c->constant(count), a), index);
2007-12-09 22:45:43 +00:00
} break;
2007-10-04 22:41:19 +00:00
2007-12-09 22:45:43 +00:00
case iload: {
frame->loadInt(codeReadInt16(t, code, ip));
} break;
2007-10-04 22:41:19 +00:00
2007-12-09 22:45:43 +00:00
case istore: {
frame->storeInt(codeReadInt16(t, code, ip));
} break;
2007-10-04 22:41:19 +00:00
2007-12-09 22:45:43 +00:00
case lload: {
frame->loadLong(codeReadInt16(t, code, ip));
} break;
2007-10-04 22:41:19 +00:00
2007-12-09 22:45:43 +00:00
case lstore: {
frame->storeLong(codeReadInt16(t, code, ip));
} break;
2007-10-12 14:26:36 +00:00
2007-12-09 22:45:43 +00:00
case ret:
c->jmp
(c->memory
(c->base(), localOffset
(t, codeReadInt16(t, code, ip), context->method)));
return;
2007-10-04 22:41:19 +00:00
2007-12-09 22:45:43 +00:00
default: abort(t);
}
} break;
default: abort(t);
2007-12-09 22:45:43 +00:00
}
}
}
2007-10-04 22:41:19 +00:00
void
logCompile(const void* code, unsigned size, const char* class_,
const char* name, const char* spec)
{
2008-04-21 00:20:38 +00:00
fprintf(stderr, "%s.%s%s: %p %p\n",
class_, name, spec, code,
static_cast<const uint8_t*>(code) + size);
}
2008-01-07 14:51:07 +00:00
void
translateExceptionHandlerTable(MyThread* t, Compiler* c, object code,
intptr_t start)
2008-01-07 14:51:07 +00:00
{
object oldTable = codeExceptionHandlerTable(t, code);
if (oldTable) {
PROTECT(t, code);
PROTECT(t, oldTable);
unsigned length = exceptionHandlerTableLength(t, oldTable);
object newIndex = makeIntArray(t, length * 3, false);
PROTECT(t, newIndex);
object newTable = makeArray(t, length + 1, true);
PROTECT(t, newTable);
set(t, newTable, ArrayBody, newIndex);
2008-01-07 14:51:07 +00:00
for (unsigned i = 0; i < length; ++i) {
ExceptionHandler* oldHandler = exceptionHandlerTableBody
(t, oldTable, i);
intArrayBody(t, newIndex, i * 3)
2008-02-11 17:21:41 +00:00
= c->machineIp(exceptionHandlerStart(oldHandler))->value() - start;
2008-01-07 14:51:07 +00:00
intArrayBody(t, newIndex, (i * 3) + 1)
2008-02-11 17:21:41 +00:00
= c->machineIp(exceptionHandlerEnd(oldHandler))->value() - start;
2008-01-07 14:51:07 +00:00
intArrayBody(t, newIndex, (i * 3) + 2)
2008-02-11 17:21:41 +00:00
= c->machineIp(exceptionHandlerIp(oldHandler))->value() - start;
2008-01-07 14:51:07 +00:00
object type;
if (exceptionHandlerCatchType(oldHandler)) {
type = resolveClassInPool
(t, codePool(t, code), exceptionHandlerCatchType(oldHandler) - 1);
if (UNLIKELY(t->exception)) return;
} else {
type = 0;
}
set(t, newTable, ArrayBody + ((i + 1) * BytesPerWord), type);
2008-01-07 14:51:07 +00:00
}
set(t, code, CodeExceptionHandlerTable, newTable);
}
}
void
translateLineNumberTable(MyThread* t, Compiler* c, object code, intptr_t start)
2008-01-07 14:51:07 +00:00
{
object oldTable = codeLineNumberTable(t, code);
if (oldTable) {
PROTECT(t, code);
PROTECT(t, oldTable);
unsigned length = lineNumberTableLength(t, oldTable);
object newTable = makeLineNumberTable(t, length, false);
for (unsigned i = 0; i < length; ++i) {
LineNumber* oldLine = lineNumberTableBody(t, oldTable, i);
LineNumber* newLine = lineNumberTableBody(t, newTable, i);
lineNumberIp(newLine)
2008-02-11 17:21:41 +00:00
= c->machineIp(lineNumberIp(oldLine))->value() - start;
2008-01-07 14:51:07 +00:00
lineNumberLine(newLine) = lineNumberLine(oldLine);
}
set(t, code, CodeLineNumberTable, newTable);
}
}
void
printSet(uintptr_t m)
{
for (unsigned i = 0; i < 16; ++i) {
if ((m >> i) & 1) {
fprintf(stderr, "1");
} else {
fprintf(stderr, "_");
}
}
}
unsigned
calculateFrameMaps(MyThread* t, Context* context, uintptr_t* originalRoots,
2008-07-05 20:21:13 +00:00
unsigned stackPadding, unsigned eventIndex)
2008-01-07 14:51:07 +00:00
{
// for each instruction with more than one predecessor, and for each
// stack position, determine if there exists a path to that
// instruction such that there is not an object pointer left at that
// stack position (i.e. it is uninitialized or contains primitive
// data).
2008-07-05 20:21:13 +00:00
Compiler* c = context->compiler;
unsigned localSize = ::localSize(t, context->method);
2008-01-07 14:51:07 +00:00
unsigned mapSize = frameMapSizeInWords(t, context->method);
uintptr_t roots[mapSize];
if (originalRoots) {
memcpy(roots, originalRoots, mapSize * BytesPerWord);
} else {
memset(roots, 0, mapSize * BytesPerWord);
}
2008-01-07 14:51:07 +00:00
int32_t ip = -1;
// invariant: for each stack position, roots contains a zero at that
// position if there exists some path to the current instruction
// such that there is definitely not an object pointer at that
// position. Otherwise, roots contains a one at that position,
// meaning either all known paths result in an object pointer at
// that position, or the contents of that position are as yet
// unknown.
unsigned length = context->eventLog.length();
while (eventIndex < length) {
Event e = static_cast<Event>(context->eventLog.get(eventIndex++));
2008-01-07 14:51:07 +00:00
switch (e) {
2008-07-05 20:21:13 +00:00
case PushContextEvent: {
eventIndex = calculateFrameMaps
(t, context, roots, stackPadding, eventIndex);
2008-01-07 14:51:07 +00:00
} break;
2008-07-05 20:21:13 +00:00
case PopContextEvent:
return eventIndex;
2008-01-07 14:51:07 +00:00
2008-07-05 20:21:13 +00:00
case PushEvent: {
Compiler::StackElement* s;
context->eventLog.get(eventIndex, &s, BytesPerWord);
stackPadding += c->padding(s);
eventIndex += BytesPerWord;
} break;
case PopEvent: {
Compiler::StackElement* s;
context->eventLog.get(eventIndex, &s, BytesPerWord);
stackPadding -= c->padding(s);
eventIndex += BytesPerWord;
} break;
2008-01-07 14:51:07 +00:00
case IpEvent: {
ip = context->eventLog.get2(eventIndex);
eventIndex += 2;
2008-01-07 14:51:07 +00:00
if (DebugFrameMaps) {
fprintf(stderr, " roots at ip %3d: ", ip);
printSet(*roots);
fprintf(stderr, "\n");
}
uintptr_t* tableRoots = context->rootTable + (ip * mapSize);
2008-01-07 14:51:07 +00:00
if (context->visitTable[ip] > 1) {
for (unsigned wi = 0; wi < mapSize; ++wi) {
uintptr_t newRoots = tableRoots[wi] & roots[wi];
if ((eventIndex == length
2008-07-05 20:21:13 +00:00
or context->eventLog.get(eventIndex) == PopContextEvent)
and newRoots != tableRoots[wi])
{
if (DebugFrameMaps) {
fprintf(stderr, "dirty roots!\n");
}
context->dirtyRoots = true;
}
tableRoots[wi] = newRoots;
roots[wi] &= tableRoots[wi];
2008-01-07 14:51:07 +00:00
}
if (DebugFrameMaps) {
fprintf(stderr, "table roots at ip %3d: ", ip);
printSet(*tableRoots);
fprintf(stderr, "\n");
}
} else {
memcpy(tableRoots, roots, mapSize * BytesPerWord);
2008-01-07 14:51:07 +00:00
}
} break;
case MarkEvent: {
unsigned i = context->eventLog.get2(eventIndex);
eventIndex += 2;
2008-01-07 14:51:07 +00:00
2008-07-05 20:21:13 +00:00
if (i > localSize) {
i += stackPadding;
}
2008-01-07 14:51:07 +00:00
markBit(roots, i);
} break;
case ClearEvent: {
unsigned i = context->eventLog.get2(eventIndex);
eventIndex += 2;
2008-07-05 20:21:13 +00:00
if (i > localSize) {
i += stackPadding;
}
clearBit(roots, i);
2008-01-07 14:51:07 +00:00
} break;
case TraceEvent: {
TraceElement* te; context->eventLog.get(eventIndex, &te, BytesPerWord);
memcpy(te->map, roots, mapSize * BytesPerWord);
eventIndex += BytesPerWord;
2008-01-07 14:51:07 +00:00
} break;
default: abort(t);
}
}
return eventIndex;
2008-01-07 14:51:07 +00:00
}
Zone*
2008-04-13 18:15:04 +00:00
codeZone(MyThread* t);
int
compareTraceElementPointers(const void* va, const void* vb)
{
TraceElement* a = *static_cast<TraceElement* const*>(va);
TraceElement* b = *static_cast<TraceElement* const*>(vb);
if (a->address->value() > b->address->value()) {
return 1;
} else if (a->address->value() < b->address->value()) {
return -1;
} else {
return 0;
}
}
2008-04-11 21:00:18 +00:00
unsigned
frameObjectMapSize(MyThread* t, object method, object map)
{
2008-07-05 20:21:13 +00:00
int size = alignedFrameSize(t, method);
2008-04-11 21:00:18 +00:00
return ceiling(intArrayLength(t, map) * size, 32 + size);
}
unsigned
codeSingletonSizeInBytes(MyThread*, unsigned codeSizeInBytes)
2007-12-09 22:45:43 +00:00
{
unsigned count = ceiling(codeSizeInBytes, BytesPerWord);
unsigned size = count + singletonMaskSize(count);
return pad(SingletonBody + (size * BytesPerWord));
}
2007-12-18 02:09:32 +00:00
2007-12-09 22:45:43 +00:00
object
2008-02-11 17:21:41 +00:00
allocateCode(MyThread* t, unsigned codeSizeInBytes)
2007-12-09 22:45:43 +00:00
{
2008-02-11 17:21:41 +00:00
unsigned count = ceiling(codeSizeInBytes, BytesPerWord);
2007-12-09 22:45:43 +00:00
unsigned size = count + singletonMaskSize(count);
object result = allocate3
2008-04-13 18:15:04 +00:00
(t, codeZone(t), Machine::ImmortalAllocation,
SingletonBody + (size * BytesPerWord), true);
initSingleton(t, result, size, true);
mark(t, result, 0);
2007-12-09 22:45:43 +00:00
singletonMask(t, result)[0] = 1;
2008-02-11 17:21:41 +00:00
return result;
}
2007-10-04 22:41:19 +00:00
2008-02-11 17:21:41 +00:00
object
finish(MyThread* t, Assembler* a, const char* name)
{
object result = allocateCode(t, a->length());
2007-12-09 22:45:43 +00:00
uint8_t* start = reinterpret_cast<uint8_t*>(&singletonValue(t, result, 0));
2007-10-04 22:41:19 +00:00
2008-02-11 17:21:41 +00:00
a->writeTo(start);
2007-10-04 22:41:19 +00:00
if (Verbose) {
logCompile(start, a->length(), 0, name, 0);
}
2007-10-04 22:41:19 +00:00
2008-02-11 17:21:41 +00:00
return result;
}
2007-10-12 14:26:36 +00:00
2008-02-11 17:21:41 +00:00
object
finish(MyThread* t, Context* context)
{
Compiler* c = context->compiler;
2008-02-11 17:21:41 +00:00
unsigned codeSize = c->compile();
object result = allocateCode(t, pad(codeSize) + c->poolSize());
PROTECT(t, result);
2008-02-11 17:21:41 +00:00
uint8_t* start = reinterpret_cast<uint8_t*>(&singletonValue(t, result, 0));
2008-02-11 17:21:41 +00:00
c->writeTo(start);
translateExceptionHandlerTable(t, c, methodCode(t, context->method),
reinterpret_cast<intptr_t>(start));
if (UNLIKELY(t->exception)) return 0;
translateLineNumberTable(t, c, methodCode(t, context->method),
reinterpret_cast<intptr_t>(start));
{ object code = methodCode(t, context->method);
2008-04-11 21:00:18 +00:00
code = makeCode(t, 0,
codeExceptionHandlerTable(t, code),
codeLineNumberTable(t, code),
codeMaxStack(t, code),
codeMaxLocals(t, code),
0, false);
set(t, context->method, MethodCode, code);
2008-02-11 17:21:41 +00:00
}
if (context->traceLogCount) {
TraceElement* elements[context->traceLogCount];
unsigned index = 0;
for (TraceElement* p = context->traceLog; p; p = p->next) {
assert(t, index < context->traceLogCount);
2008-04-11 21:00:18 +00:00
elements[index++] = p;
if (p->target) {
insertCallNode
(t, makeCallNode
(t, p->address->value(), p->target, p->virtualCall, 0));
2007-12-09 22:45:43 +00:00
}
}
qsort(elements, context->traceLogCount, sizeof(TraceElement*),
compareTraceElementPointers);
2008-07-05 20:21:13 +00:00
unsigned size = alignedFrameSize(t, context->method);
object map = makeIntArray
(t, context->traceLogCount
+ ceiling(context->traceLogCount * size, 32),
false);
assert(t, intArrayLength(t, map) == context->traceLogCount
+ frameObjectMapSize(t, context->method, map));
2008-04-11 21:00:18 +00:00
for (unsigned i = 0; i < context->traceLogCount; ++i) {
TraceElement* p = elements[i];
intArrayBody(t, map, i) = static_cast<intptr_t>(p->address->value())
- reinterpret_cast<intptr_t>(start);
for (unsigned j = 0; j < size; ++j) {
unsigned index = ((i * size) + j);
int32_t* v = &intArrayBody
(t, map, context->traceLogCount + (index / 32));
if (getBit(p->map, j)) {
*v |= static_cast<int32_t>(1) << (index % 32);
} else {
*v &= ~(static_cast<int32_t>(1) << (index % 32));
}
}
2007-12-09 22:45:43 +00:00
}
set(t, methodCode(t, context->method), CodePool, map);
}
2008-04-18 04:16:20 +00:00
for (PoolElement* p = context->objectPool; p; p = p->next) {
intptr_t offset = p->address->value() - reinterpret_cast<intptr_t>(start);
2008-04-18 04:16:20 +00:00
singletonMarkObject(t, result, offset / BytesPerWord);
2008-04-18 04:16:20 +00:00
set(t, result, SingletonBody + offset, p->value);
}
2007-12-13 00:18:31 +00:00
2008-02-11 17:21:41 +00:00
if (Verbose) {
logCompile
2008-04-17 22:07:32 +00:00
(start, codeSize,
2008-02-11 17:21:41 +00:00
reinterpret_cast<const char*>
(&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)),
reinterpret_cast<const char*>
(&byteArrayBody(t, methodName(t, context->method), 0)),
reinterpret_cast<const char*>
(&byteArrayBody(t, methodSpec(t, context->method), 0)));
}
// for debugging:
if (false and
2008-02-11 17:21:41 +00:00
strcmp
(reinterpret_cast<const char*>
(&byteArrayBody(t, className(t, methodClass(t, context->method)), 0)),
"java/lang/String") == 0 and
2008-02-11 17:21:41 +00:00
strcmp
(reinterpret_cast<const char*>
(&byteArrayBody(t, methodName(t, context->method), 0)),
"compareTo") == 0)
2008-02-11 17:21:41 +00:00
{
asm("int3");
2007-12-09 22:45:43 +00:00
}
2007-12-09 22:45:43 +00:00
return result;
}
2007-09-30 02:48:27 +00:00
2007-12-09 22:45:43 +00:00
object
compile(MyThread* t, Context* context)
2007-12-09 22:45:43 +00:00
{
2008-02-11 17:21:41 +00:00
Compiler* c = context->compiler;
2007-09-30 02:48:27 +00:00
// fprintf(stderr, "compiling %s.%s%s\n",
// &byteArrayBody(t, className(t, methodClass(t, context->method)), 0),
// &byteArrayBody(t, methodName(t, context->method), 0),
// &byteArrayBody(t, methodSpec(t, context->method), 0));
unsigned footprint = methodParameterFootprint(t, context->method);
unsigned locals = localSize(t, context->method);
c->init(codeLength(t, methodCode(t, context->method)), footprint, locals);
2007-09-30 02:48:27 +00:00
2008-02-11 17:21:41 +00:00
uint8_t stackMap[codeMaxStack(t, methodCode(t, context->method))];
2008-01-07 14:51:07 +00:00
Frame frame(context, stackMap);
2007-09-30 02:48:27 +00:00
2008-01-07 14:51:07 +00:00
unsigned index = 0;
if ((methodFlags(t, context->method) & ACC_STATIC) == 0) {
2008-02-11 17:21:41 +00:00
frame.set(index++, Frame::Object);
2008-01-07 14:51:07 +00:00
}
for (MethodSpecIterator it
(t, reinterpret_cast<const char*>
(&byteArrayBody(t, methodSpec(t, context->method), 0)));
it.hasNext();)
{
2008-01-07 14:51:07 +00:00
switch (*it.next()) {
case 'L':
case '[':
2008-02-11 17:21:41 +00:00
frame.set(index++, Frame::Object);
2008-01-07 14:51:07 +00:00
break;
case 'J':
case 'D':
2008-02-11 17:21:41 +00:00
frame.set(index++, Frame::Long);
frame.set(index++, Frame::Long);
2008-01-07 14:51:07 +00:00
break;
default:
2008-02-11 17:21:41 +00:00
frame.set(index++, Frame::Integer);
2008-01-07 14:51:07 +00:00
break;
}
}
2007-12-09 22:45:43 +00:00
compile(t, &frame, 0);
if (UNLIKELY(t->exception)) return 0;
2007-09-30 02:48:27 +00:00
context->dirtyRoots = false;
2008-07-05 20:21:13 +00:00
unsigned eventIndex = calculateFrameMaps(t, context, 0, 0, 0);
2008-01-07 14:51:07 +00:00
object eht = codeExceptionHandlerTable(t, methodCode(t, context->method));
2007-12-09 22:45:43 +00:00
if (eht) {
PROTECT(t, eht);
2007-09-30 02:48:27 +00:00
unsigned visitCount = exceptionHandlerTableLength(t, eht);
bool visited[visitCount];
memset(visited, 0, visitCount);
while (visitCount) {
bool progress = false;
for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) {
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
unsigned start = exceptionHandlerStart(eh);
if (not visited[i] and context->visitTable[start]) {
-- visitCount;
visited[i] = true;
progress = true;
2008-02-11 17:21:41 +00:00
uint8_t stackMap[codeMaxStack(t, methodCode(t, context->method))];
Frame frame2(&frame, stackMap);
uintptr_t* roots = context->rootTable
+ (start * frameMapSizeInWords(t, context->method));
for (unsigned i = 0; i < localSize(t, context->method); ++ i) {
if (getBit(roots, i)) {
2008-02-11 17:21:41 +00:00
frame2.set(i, Frame::Object);
} else {
2008-02-11 17:21:41 +00:00
frame2.set(i, Frame::Integer);
}
}
2007-09-30 02:48:27 +00:00
for (unsigned i = 1;
i < codeMaxStack(t, methodCode(t, context->method));
++i)
{
2008-02-11 17:21:41 +00:00
frame2.set(localSize(t, context->method) + i, Frame::Integer);
}
2008-01-07 14:51:07 +00:00
2008-04-09 19:08:13 +00:00
compile(t, &frame2, exceptionHandlerIp(eh), true);
if (UNLIKELY(t->exception)) return 0;
2008-07-05 20:21:13 +00:00
eventIndex = calculateFrameMaps(t, context, 0, 0, eventIndex);
}
}
assert(t, progress);
2007-12-09 22:45:43 +00:00
}
}
2007-09-30 02:48:27 +00:00
while (context->dirtyRoots) {
context->dirtyRoots = false;
2008-07-05 20:21:13 +00:00
calculateFrameMaps(t, context, 0, 0, 0);
}
2008-02-11 17:21:41 +00:00
return finish(t, context);
2007-12-09 22:45:43 +00:00
}
2007-09-30 02:48:27 +00:00
2007-12-09 22:45:43 +00:00
void
compile(MyThread* t, object method);
2007-09-30 02:48:27 +00:00
2007-12-09 22:45:43 +00:00
void*
2007-12-16 22:41:07 +00:00
compileMethod2(MyThread* t)
2007-12-09 22:45:43 +00:00
{
object node = findCallNode(t, *static_cast<void**>(t->stack));
2007-12-16 22:41:07 +00:00
PROTECT(t, node);
object target = callNodeTarget(t, node);
2007-12-16 22:41:07 +00:00
PROTECT(t, target);
2007-09-30 02:48:27 +00:00
if (callNodeVirtualCall(t, node)) {
target = resolveTarget(t, t->stack, target);
2007-12-18 00:22:37 +00:00
}
2007-12-09 22:45:43 +00:00
if (LIKELY(t->exception == 0)) {
compile(t, target);
}
2007-12-09 22:45:43 +00:00
if (UNLIKELY(t->exception)) {
2007-12-16 22:41:07 +00:00
return 0;
2007-12-09 22:45:43 +00:00
} else {
if (callNodeVirtualCall(t, node)) {
classVtable
(t, objectClass
(t, resolveThisPointer(t, t->stack, target)), methodOffset(t, target))
= &singletonValue(t, methodCompiled(t, target), 0);
} else {
Context context(t);
2008-02-11 17:21:41 +00:00
context.assembler->updateCall
(reinterpret_cast<void*>(callNodeAddress(t, node)),
&singletonValue(t, methodCompiled(t, target), 0));
2007-12-09 22:45:43 +00:00
}
return &singletonValue(t, methodCompiled(t, target), 0);
}
}
2007-09-30 02:48:27 +00:00
2008-07-05 20:21:13 +00:00
void*
2007-12-16 22:41:07 +00:00
compileMethod(MyThread* t)
{
void* r = compileMethod2(t);
if (UNLIKELY(t->exception)) {
unwind(t);
} else {
return r;
}
}
2007-12-09 22:45:43 +00:00
uint64_t
invokeNative2(MyThread* t, object method)
{
PROTECT(t, method);
assert(t, methodFlags(t, method) & ACC_NATIVE);
2008-01-08 19:36:34 +00:00
initClass(t, methodClass(t, method));
if (UNLIKELY(t->exception)) return 0;
if (methodCode(t, method) == 0) {
2007-12-09 22:45:43 +00:00
void* function = resolveNativeMethod(t, method);
if (UNLIKELY(function == 0)) {
object message = makeString
2008-01-31 00:08:47 +00:00
(t, "%s.%s%s",
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
&byteArrayBody(t, methodName(t, method), 0),
&byteArrayBody(t, methodSpec(t, method), 0));
2007-12-09 22:45:43 +00:00
t->exception = makeUnsatisfiedLinkError(t, message);
return 0;
}
2007-12-09 22:45:43 +00:00
object p = makePointer(t, function);
set(t, method, MethodCode, p);
}
2007-12-09 22:45:43 +00:00
object class_ = methodClass(t, method);
PROTECT(t, class_);
2007-12-09 22:45:43 +00:00
unsigned footprint = methodParameterFootprint(t, method) + 1;
if (methodFlags(t, method) & ACC_STATIC) {
++ footprint;
}
2008-01-03 19:49:07 +00:00
unsigned count = methodParameterCount(t, method) + 2;
2007-12-09 22:45:43 +00:00
uintptr_t args[footprint];
unsigned argOffset = 0;
uint8_t types[count];
unsigned typeOffset = 0;
2007-09-30 02:48:27 +00:00
2007-12-09 22:45:43 +00:00
args[argOffset++] = reinterpret_cast<uintptr_t>(t);
types[typeOffset++] = POINTER_TYPE;
2007-12-09 22:45:43 +00:00
uintptr_t* sp = static_cast<uintptr_t*>(t->stack)
2007-12-15 01:11:01 +00:00
+ methodParameterFootprint(t, method);
2007-12-09 22:45:43 +00:00
if (methodFlags(t, method) & ACC_STATIC) {
args[argOffset++] = reinterpret_cast<uintptr_t>(&class_);
} else {
args[argOffset++] = reinterpret_cast<uintptr_t>(sp--);
}
types[typeOffset++] = POINTER_TYPE;
2007-12-09 22:45:43 +00:00
MethodSpecIterator it
(t, reinterpret_cast<const char*>
(&byteArrayBody(t, methodSpec(t, method), 0)));
while (it.hasNext()) {
unsigned type = types[typeOffset++]
= fieldType(t, fieldCode(t, *it.next()));
2007-12-09 22:45:43 +00:00
switch (type) {
case INT8_TYPE:
case INT16_TYPE:
case INT32_TYPE:
case FLOAT_TYPE:
args[argOffset++] = *(sp--);
break;
2007-12-09 22:45:43 +00:00
case INT64_TYPE:
case DOUBLE_TYPE: {
2007-12-23 19:18:34 +00:00
memcpy(args + argOffset, sp - 1, 8);
2007-12-18 02:09:32 +00:00
argOffset += (8 / BytesPerWord);
2007-12-18 00:22:37 +00:00
sp -= 2;
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
case POINTER_TYPE: {
if (*sp) {
args[argOffset++] = reinterpret_cast<uintptr_t>(sp);
} else {
args[argOffset++] = 0;
}
-- sp;
2007-12-09 22:45:43 +00:00
} break;
2007-12-09 22:45:43 +00:00
default: abort(t);
2007-10-03 00:22:48 +00:00
}
}
2007-12-09 22:45:43 +00:00
void* function = pointerValue(t, methodCode(t, method));
unsigned returnCode = methodReturnCode(t, method);
unsigned returnType = fieldType(t, returnCode);
2007-12-09 22:45:43 +00:00
uint64_t result;
if (DebugNatives) {
2007-12-09 22:45:43 +00:00
fprintf(stderr, "invoke native method %s.%s\n",
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
&byteArrayBody(t, methodName(t, method), 0));
}
2007-10-04 00:41:54 +00:00
if (methodFlags(t, method) & ACC_SYNCHRONIZED) {
if (methodFlags(t, method) & ACC_STATIC) {
acquire(t, methodClass(t, method));
} else {
acquire(t, *reinterpret_cast<object*>(args[0]));
}
}
Reference* reference = t->reference;
2007-12-09 22:45:43 +00:00
{ ENTER(t, Thread::IdleState);
2007-10-03 00:22:48 +00:00
2007-12-09 22:45:43 +00:00
result = t->m->system->call
(function,
args,
types,
2008-01-03 19:49:07 +00:00
count,
2007-12-09 22:45:43 +00:00
footprint * BytesPerWord,
returnType);
}
2007-09-25 23:53:11 +00:00
if (methodFlags(t, method) & ACC_SYNCHRONIZED) {
if (methodFlags(t, method) & ACC_STATIC) {
release(t, methodClass(t, method));
} else {
release(t, *reinterpret_cast<object*>(args[0]));
}
}
if (DebugNatives) {
2007-12-09 22:45:43 +00:00
fprintf(stderr, "return from native method %s.%s\n",
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
&byteArrayBody(t, methodName(t, method), 0));
2007-10-03 00:22:48 +00:00
}
if (LIKELY(t->exception == 0)) {
switch (returnCode) {
case ByteField:
case BooleanField:
result = static_cast<int8_t>(result);
break;
case CharField:
result = static_cast<uint16_t>(result);
break;
case ShortField:
result = static_cast<int16_t>(result);
break;
case FloatField:
case IntField:
result = static_cast<int32_t>(result);
break;
2007-12-18 02:09:32 +00:00
case LongField:
case DoubleField:
result = result;
break;
case ObjectField:
result = static_cast<uintptr_t>(result) ? *reinterpret_cast<uintptr_t*>
(static_cast<uintptr_t>(result)) : 0;
break;
case VoidField:
result = 0;
break;
default: abort(t);
2007-12-18 02:09:32 +00:00
}
2007-12-09 22:45:43 +00:00
} else {
result = 0;
2007-10-03 00:22:48 +00:00
}
while (t->reference != reference) {
dispose(t, t->reference);
}
return result;
2007-12-09 22:45:43 +00:00
}
2008-07-05 20:21:13 +00:00
uint64_t
2007-12-09 22:45:43 +00:00
invokeNative(MyThread* t)
{
if (t->trace->nativeMethod == 0) {
object node = findCallNode(t, *static_cast<void**>(t->stack));
2008-04-23 16:33:31 +00:00
object target = callNodeTarget(t, node);
if (callNodeVirtualCall(t, node)) {
2008-04-23 16:33:31 +00:00
target = resolveTarget(t, t->stack, target);
2008-04-01 17:37:59 +00:00
}
2008-04-23 16:33:31 +00:00
t->trace->nativeMethod = target;
}
2008-04-01 17:37:59 +00:00
uint64_t result = 0;
2007-10-03 00:22:48 +00:00
2007-12-09 22:45:43 +00:00
if (LIKELY(t->exception == 0)) {
result = invokeNative2(t, t->trace->nativeMethod);
2007-10-03 00:22:48 +00:00
}
t->trace->nativeMethod = 0;
2007-12-09 22:45:43 +00:00
if (UNLIKELY(t->exception)) {
unwind(t);
} else {
return result;
2007-10-03 00:22:48 +00:00
}
2007-12-09 22:45:43 +00:00
}
unsigned
frameMapIndex(MyThread* t, object method, int32_t offset)
{
object map = codePool(t, methodCode(t, method));
2008-04-11 21:00:18 +00:00
unsigned mapSize = frameObjectMapSize(t, method, map);
unsigned indexSize = intArrayLength(t, map) - mapSize;
unsigned bottom = 0;
unsigned top = indexSize;
for (unsigned span = top - bottom; span; span = top - bottom) {
unsigned middle = bottom + (span / 2);
int32_t v = intArrayBody(t, map, middle);
if (offset == v) {
2008-07-05 20:21:13 +00:00
return (indexSize * 32) + (alignedFrameSize(t, method) * middle);
} else if (offset < v) {
top = middle;
} else {
bottom = middle + 1;
}
}
abort(t);
}
2007-10-03 00:22:48 +00:00
2007-12-09 22:45:43 +00:00
void
visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* base, object method,
void* ip, void* calleeBase, unsigned argumentFootprint)
2007-12-09 22:45:43 +00:00
{
2008-01-07 14:51:07 +00:00
unsigned count;
if (calleeBase) {
unsigned parameterFootprint = methodParameterFootprint(t, method);
unsigned height = static_cast<uintptr_t*>(base)
- static_cast<uintptr_t*>(calleeBase) - 2;
2007-12-09 22:45:43 +00:00
2008-01-07 14:51:07 +00:00
count = parameterFootprint + height - argumentFootprint;
} else {
2008-07-05 20:21:13 +00:00
count = alignedFrameSize(t, method);
2007-12-09 22:45:43 +00:00
}
if (count) {
object map = codePool(t, methodCode(t, method));
int index = frameMapIndex
(t, method, difference
(ip, &singletonValue(t, methodCompiled(t, method), 0)));
2007-12-09 22:45:43 +00:00
for (unsigned i = 0; i < count; ++i) {
int j = index + i;
if ((intArrayBody(t, map, j / 32)
& (static_cast<int32_t>(1) << (j % 32))))
{
v->visit(localObject(t, base, method, i));
}
2007-09-25 23:53:11 +00:00
}
}
}
void
2007-12-09 22:45:43 +00:00
visitStack(MyThread* t, Heap::Visitor* v)
{
2007-12-30 22:24:48 +00:00
void* ip = t->ip;
2007-12-09 22:45:43 +00:00
void* base = t->base;
void** stack = static_cast<void**>(t->stack);
2008-01-02 01:07:12 +00:00
if (ip == 0 and stack) {
2007-12-30 22:24:48 +00:00
ip = *stack;
}
2007-12-09 22:45:43 +00:00
MyThread::CallTrace* trace = t->trace;
2008-01-07 14:51:07 +00:00
void* calleeBase = 0;
unsigned argumentFootprint = 0;
2007-12-09 22:45:43 +00:00
2007-12-16 22:41:07 +00:00
while (stack) {
object method = methodForIp(t, ip);
if (method) {
PROTECT(t, method);
visitStackAndLocals
(t, v, base, method, ip, calleeBase, argumentFootprint);
2008-01-07 14:51:07 +00:00
calleeBase = base;
argumentFootprint = methodParameterFootprint(t, method);
2007-12-09 22:45:43 +00:00
stack = static_cast<void**>(base) + 1;
2008-01-02 01:07:12 +00:00
if (stack) {
ip = *stack;
}
2007-12-09 22:45:43 +00:00
base = *static_cast<void**>(base);
} else if (trace) {
2008-01-07 14:51:07 +00:00
calleeBase = 0;
argumentFootprint = 0;
2007-12-09 22:45:43 +00:00
base = trace->base;
stack = static_cast<void**>(trace->stack);
2008-01-02 01:07:12 +00:00
if (stack) {
ip = *stack;
}
2007-12-09 22:45:43 +00:00
trace = trace->next;
} else {
break;
}
}
2007-12-09 22:45:43 +00:00
}
2008-02-11 17:21:41 +00:00
void
2008-08-16 17:45:36 +00:00
saveFrame(MyThread* t, Assembler* a)
{
Assembler::Register frame(a->frame());
Assembler::Memory frameDst(a->thread(), difference(&(t->frame), t));
a->apply(Move, BytesPerWord, RegisterOperand, &frame,
BytesPerWord, MemoryOperand, &frameDst);
}
void
pushFrame(MyThread* t, Assembler* a, unsigned size)
2007-12-09 22:45:43 +00:00
{
2008-08-16 17:45:36 +00:00
Assembler::Constant offset(resolved(c, Assembler::alignFrameSize(size)));
a->apply(PushFrame, BytesPerWord, ConstantOperand, &offset);
}
2008-02-11 17:21:41 +00:00
void
2008-08-16 17:45:36 +00:00
setThreadArgument(MyThread*, Assembler* a)
{
2008-02-11 17:21:41 +00:00
Assembler::Register thread(a->thread());
2008-02-11 17:21:41 +00:00
if (a->argumentRegisterCount()) {
Assembler::Register arg(a->argumentRegister(0));
2008-04-17 22:07:32 +00:00
a->apply(Move, BytesPerWord, RegisterOperand, &thread,
2008-08-16 17:45:36 +00:00
BytesPerWord, RegisterOperand, &arg);
2008-02-11 17:21:41 +00:00
} else {
2008-08-16 17:45:36 +00:00
Assembler::Memory arg(a->frame(), a->argumentPosition(0));
a->apply(Move, BytesPerWord, RegisterOperand, &thread,
BytesPerWord, MemoryOperand, &arg);
2008-02-17 22:29:04 +00:00
}
}
2007-09-25 23:53:11 +00:00
class ArgumentList {
public:
ArgumentList(Thread* t, uintptr_t* array, bool* objectMask, object this_,
const char* spec, bool indirectObjects, va_list arguments):
t(static_cast<MyThread*>(t)),
array(array),
objectMask(objectMask),
position(0),
protector(this)
2007-09-25 23:53:11 +00:00
{
if (this_) {
addObject(this_);
}
for (MethodSpecIterator it(t, spec); it.hasNext();) {
switch (*it.next()) {
2007-09-25 23:53:11 +00:00
case 'L':
case '[':
if (indirectObjects) {
object* v = va_arg(arguments, object*);
addObject(v ? *v : 0);
} else {
addObject(va_arg(arguments, object));
}
break;
case 'J':
case 'D':
addLong(va_arg(arguments, uint64_t));
break;
2007-09-25 23:53:11 +00:00
default:
addInt(va_arg(arguments, uint32_t));
break;
2007-09-25 23:53:11 +00:00
}
}
2007-09-25 23:53:11 +00:00
}
ArgumentList(Thread* t, uintptr_t* array, bool* objectMask, object this_,
const char* spec, object arguments):
t(static_cast<MyThread*>(t)),
array(array),
objectMask(objectMask),
position(0),
protector(this)
2007-09-25 23:53:11 +00:00
{
if (this_) {
addObject(this_);
}
unsigned index = 0;
for (MethodSpecIterator it(t, spec); it.hasNext();) {
switch (*it.next()) {
2007-09-25 23:53:11 +00:00
case 'L':
case '[':
addObject(objectArrayBody(t, arguments, index++));
break;
case 'J':
case 'D':
addLong(cast<int64_t>(objectArrayBody(t, arguments, index++),
BytesPerWord));
break;
default:
addInt(cast<int32_t>(objectArrayBody(t, arguments, index++),
BytesPerWord));
break;
2007-09-25 23:53:11 +00:00
}
}
}
void addObject(object v) {
array[position] = reinterpret_cast<uintptr_t>(v);
objectMask[position] = true;
++ position;
}
2007-10-12 22:06:33 +00:00
void addInt(uintptr_t v) {
2007-09-25 23:53:11 +00:00
array[position] = v;
objectMask[position] = false;
++ position;
}
void addLong(uint64_t v) {
2007-12-23 20:06:24 +00:00
if (BytesPerWord == 8) {
memcpy(array + position + 1, &v, 8);
} else {
// push words in reverse order, since they will be switched back
// when pushed on the stack:
array[position] = v >> 32;
array[position + 1] = v;
2007-12-23 20:06:24 +00:00
}
2007-09-25 23:53:11 +00:00
objectMask[position] = false;
2007-12-23 20:06:24 +00:00
objectMask[position + 1] = false;
2007-09-25 23:53:11 +00:00
position += 2;
}
MyThread* t;
uintptr_t* array;
bool* objectMask;
unsigned position;
class MyProtector: public Thread::Protector {
public:
MyProtector(ArgumentList* list): Protector(list->t), list(list) { }
virtual void visit(Heap::Visitor* v) {
for (unsigned i = 0; i < list->position; ++i) {
if (list->objectMask[i]) {
v->visit(reinterpret_cast<object*>(list->array + i));
}
}
}
ArgumentList* list;
} protector;
2007-09-25 23:53:11 +00:00
};
object
invoke(Thread* thread, object method, ArgumentList* arguments)
{
MyThread* t = static_cast<MyThread*>(thread);
unsigned returnCode = methodReturnCode(t, method);
2007-09-25 23:53:11 +00:00
unsigned returnType = fieldType(t, returnCode);
2007-12-30 22:24:48 +00:00
uint64_t result;
2007-09-30 02:48:27 +00:00
2007-12-30 22:24:48 +00:00
{ MyThread::CallTrace trace(t);
if (methodFlags(t, method) & ACC_NATIVE) {
trace.nativeMethod = method;
}
2007-12-30 22:24:48 +00:00
result = vmInvoke
(t, &singletonValue(t, methodCompiled(t, method), 0), arguments->array,
arguments->position, returnType);
}
2007-09-25 23:53:11 +00:00
if (t->exception) {
if (t->backupHeap) {
collect(t, Heap::MinorCollection);
}
return 0;
}
2007-09-25 23:53:11 +00:00
object r;
switch (returnCode) {
case ByteField:
case BooleanField:
case CharField:
case ShortField:
case FloatField:
case IntField:
r = makeInt(t, result);
break;
case LongField:
case DoubleField:
r = makeLong(t, result);
break;
case ObjectField:
2007-12-16 00:24:15 +00:00
r = reinterpret_cast<object>(result);
2007-09-25 23:53:11 +00:00
break;
case VoidField:
r = 0;
break;
default:
abort(t);
};
return r;
}
2007-12-30 22:24:48 +00:00
class SegFaultHandler: public System::SignalHandler {
public:
SegFaultHandler(): m(0) { }
virtual bool handleSignal(void** ip, void** base, void** stack,
void** thread)
{
2007-12-30 22:24:48 +00:00
MyThread* t = static_cast<MyThread*>(m->localThread->get());
2008-01-02 01:07:12 +00:00
if (t->state == Thread::ActiveState) {
object node = methodForIp(t, *ip);
2008-01-02 01:07:12 +00:00
if (node) {
2008-04-23 16:33:31 +00:00
void* oldIp = t->ip;
void* oldBase = t->base;
void* oldStack = t->stack;
2008-01-02 01:07:12 +00:00
t->ip = *ip;
t->base = *base;
t->stack = *stack;
2008-04-09 19:08:13 +00:00
ensure(t, FixedSizeOfNullPointerException + traceSize(t));
t->tracing = true;
2008-01-02 01:07:12 +00:00
t->exception = makeNullPointerException(t);
t->tracing = false;
2008-01-02 01:07:12 +00:00
findUnwindTarget(t, ip, base, stack);
2008-04-23 16:33:31 +00:00
t->ip = oldIp;
t->base = oldBase;
t->stack = oldStack;
2008-01-02 01:07:12 +00:00
*thread = t;
return true;
}
2007-12-30 22:24:48 +00:00
}
2008-01-02 01:07:12 +00:00
return false;
2007-12-30 22:24:48 +00:00
}
Machine* m;
};
class MyProcessor;
MyProcessor*
processor(MyThread* t);
2007-09-25 23:53:11 +00:00
class MyProcessor: public Processor {
public:
2008-04-13 18:15:04 +00:00
class CodeAllocator: public Allocator {
public:
CodeAllocator(System* s): s(s) { }
virtual void* tryAllocate(unsigned size) {
return s->tryAllocateExecutable(size);
}
virtual void* allocate(unsigned size) {
void* p = tryAllocate(size);
expect(s, p);
return p;
}
virtual void free(const void* p, unsigned size) {
s->freeExecutable(p, size);
}
System* s;
};
MyProcessor(System* s, Allocator* allocator):
2007-09-25 23:53:11 +00:00
s(s),
allocator(allocator),
defaultThunk(0),
nativeThunk(0),
aioobThunk(0),
callTable(0),
callTableSize(0),
methodTree(0),
methodTreeSentinal(0),
2008-04-13 18:15:04 +00:00
codeAllocator(s),
codeZone(s, &codeAllocator, 64 * 1024)
{ }
2007-09-25 23:53:11 +00:00
virtual Thread*
makeThread(Machine* m, object javaThread, Thread* parent)
{
2008-04-13 18:15:04 +00:00
MyThread* t = new (m->heap->allocate(sizeof(MyThread)))
MyThread(m, javaThread, parent);
t->init();
return t;
2007-09-25 23:53:11 +00:00
}
2007-12-09 22:45:43 +00:00
virtual object
makeMethod(vm::Thread* t,
uint8_t vmFlags,
uint8_t returnCode,
uint8_t parameterCount,
uint8_t parameterFootprint,
uint16_t flags,
uint16_t offset,
object name,
object spec,
object class_,
object code)
2007-10-04 03:19:39 +00:00
{
2007-12-09 22:45:43 +00:00
return vm::makeMethod
(t, vmFlags, returnCode, parameterCount, parameterFootprint, flags,
offset, name, spec, class_, code,
::defaultThunk(static_cast<MyThread*>(t)));
2007-10-04 03:19:39 +00:00
}
2007-12-09 22:45:43 +00:00
virtual object
makeClass(vm::Thread* t,
uint16_t flags,
uint8_t vmFlags,
uint8_t arrayDimensions,
uint16_t fixedSize,
uint16_t arrayElementSize,
object objectMask,
object name,
object super,
object interfaceTable,
object virtualTable,
object fieldTable,
object methodTable,
object staticTable,
object loader,
unsigned vtableLength)
{
2007-12-11 21:26:59 +00:00
return vm::makeClass
2007-12-09 22:45:43 +00:00
(t, flags, vmFlags, arrayDimensions, fixedSize, arrayElementSize,
objectMask, name, super, interfaceTable, virtualTable, fieldTable,
methodTable, staticTable, loader, vtableLength, false);
2007-12-11 21:26:59 +00:00
}
2007-12-11 21:26:59 +00:00
virtual void
initVtable(Thread* t, object c)
{
void* compiled = &singletonBody
(t, ::defaultThunk(static_cast<MyThread*>(t)), 0);
for (unsigned i = 0; i < classLength(t, c); ++i) {
classVtable(t, c, i) = compiled;
}
}
virtual void
initClass(Thread* t, object c)
{
PROTECT(t, c);
ACQUIRE(t, t->m->classLock);
if (classVmFlags(t, c) & NeedInitFlag
and (classVmFlags(t, c) & InitFlag) == 0)
{
classVmFlags(t, c) |= InitFlag;
invoke(t, classInitializer(t, c), 0);
if (t->exception) {
t->exception = makeExceptionInInitializerError(t, t->exception);
}
classVmFlags(t, c) &= ~(NeedInitFlag | InitFlag);
}
}
2007-09-25 23:53:11 +00:00
virtual void
visitObjects(Thread* vmt, Heap::Visitor* v)
2007-09-25 23:53:11 +00:00
{
MyThread* t = static_cast<MyThread*>(vmt);
2007-12-09 22:45:43 +00:00
if (t == t->m->rootThread) {
v->visit(&defaultThunk);
v->visit(&nativeThunk);
v->visit(&aioobThunk);
v->visit(&thunkTable);
v->visit(&callTable);
v->visit(&methodTree);
v->visit(&methodTreeSentinal);
}
2007-09-25 23:53:11 +00:00
for (MyThread::CallTrace* trace = t->trace; trace; trace = trace->next) {
v->visit(&(trace->nativeMethod));
}
2008-04-01 17:37:59 +00:00
2007-12-09 22:45:43 +00:00
for (Reference* r = t->reference; r; r = r->next) {
v->visit(&(r->target));
}
2007-09-25 23:53:11 +00:00
2007-12-09 22:45:43 +00:00
visitStack(t, v);
2007-09-25 23:53:11 +00:00
}
2007-12-09 22:45:43 +00:00
virtual void
walkStack(Thread* vmt, StackVisitor* v)
2007-09-25 23:53:11 +00:00
{
2007-12-09 22:45:43 +00:00
MyThread* t = static_cast<MyThread*>(vmt);
2007-09-25 23:53:11 +00:00
2007-12-09 22:45:43 +00:00
MyStackWalker walker(t);
walker.walk(v);
2007-09-25 23:53:11 +00:00
}
2007-10-04 22:41:19 +00:00
virtual int
2007-12-09 22:45:43 +00:00
lineNumber(Thread* vmt, object method, int ip)
2007-10-04 22:41:19 +00:00
{
2007-12-09 22:45:43 +00:00
return findLineNumber(static_cast<MyThread*>(vmt), method, ip);
2007-10-04 22:41:19 +00:00
}
2007-09-25 23:53:11 +00:00
virtual object*
makeLocalReference(Thread* vmt, object o)
2007-09-25 23:53:11 +00:00
{
if (o) {
MyThread* t = static_cast<MyThread*>(vmt);
PROTECT(t, o);
2008-04-13 18:15:04 +00:00
Reference* r = new (t->m->heap->allocate(sizeof(Reference)))
Reference(o, &(t->reference));
return &(r->target);
} else {
return 0;
}
2007-09-25 23:53:11 +00:00
}
virtual void
disposeLocalReference(Thread* t, object* r)
2007-09-25 23:53:11 +00:00
{
if (r) {
vm::dispose(t, reinterpret_cast<Reference*>(r));
}
2007-09-25 23:53:11 +00:00
}
virtual object
invokeArray(Thread* t, object method, object this_, object arguments)
{
2008-04-01 17:37:59 +00:00
if (UNLIKELY(t->exception)) return 0;
assert(t, t->state == Thread::ActiveState
or t->state == Thread::ExclusiveState);
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
2007-09-25 23:53:11 +00:00
const char* spec = reinterpret_cast<char*>
(&byteArrayBody(t, methodSpec(t, method), 0));
2007-12-09 22:45:43 +00:00
unsigned size = methodParameterFootprint(t, method);
2007-09-25 23:53:11 +00:00
uintptr_t array[size];
bool objectMask[size];
ArgumentList list(t, array, objectMask, this_, spec, arguments);
2007-12-09 22:45:43 +00:00
PROTECT(t, method);
compile(static_cast<MyThread*>(t), method);
if (LIKELY(t->exception == 0)) {
return ::invoke(t, method, &list);
}
return 0;
}
virtual object
invokeList(Thread* t, object method, object this_, bool indirectObjects,
va_list arguments)
{
2008-04-01 17:37:59 +00:00
if (UNLIKELY(t->exception)) return 0;
assert(t, t->state == Thread::ActiveState
or t->state == Thread::ExclusiveState);
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
2007-09-25 23:53:11 +00:00
const char* spec = reinterpret_cast<char*>
(&byteArrayBody(t, methodSpec(t, method), 0));
2007-12-09 22:45:43 +00:00
unsigned size = methodParameterFootprint(t, method);
2007-09-25 23:53:11 +00:00
uintptr_t array[size];
bool objectMask[size];
ArgumentList list
(t, array, objectMask, this_, spec, indirectObjects, arguments);
2007-12-09 22:45:43 +00:00
PROTECT(t, method);
compile(static_cast<MyThread*>(t), method);
if (LIKELY(t->exception == 0)) {
return ::invoke(t, method, &list);
}
return 0;
}
virtual object
invokeList(Thread* t, const char* className, const char* methodName,
const char* methodSpec, object this_, va_list arguments)
{
2008-04-01 17:37:59 +00:00
if (UNLIKELY(t->exception)) return 0;
assert(t, t->state == Thread::ActiveState
or t->state == Thread::ExclusiveState);
2007-12-09 22:45:43 +00:00
unsigned size = parameterFootprint(t, methodSpec, false);
2007-09-25 23:53:11 +00:00
uintptr_t array[size];
bool objectMask[size];
ArgumentList list
(t, array, objectMask, this_, methodSpec, false, arguments);
object method = resolveMethod(t, className, methodName, methodSpec);
if (LIKELY(t->exception == 0)) {
assert(t, ((methodFlags(t, method) & ACC_STATIC) == 0) xor (this_ == 0));
2007-12-09 22:45:43 +00:00
PROTECT(t, method);
compile(static_cast<MyThread*>(t), method);
2007-12-09 22:45:43 +00:00
if (LIKELY(t->exception == 0)) {
return ::invoke(t, method, &list);
}
2007-10-03 00:22:48 +00:00
}
2007-12-09 22:45:43 +00:00
return 0;
}
2007-10-03 00:22:48 +00:00
2007-12-30 22:24:48 +00:00
virtual void dispose(Thread* vmt) {
MyThread* t = static_cast<MyThread*>(vmt);
2007-12-11 21:26:59 +00:00
while (t->reference) {
vm::dispose(t, t->reference);
}
2008-04-13 18:15:04 +00:00
t->m->heap->free(t, sizeof(*t));
2007-12-11 21:26:59 +00:00
}
2007-12-09 22:45:43 +00:00
virtual void dispose() {
2008-04-13 18:15:04 +00:00
codeZone.dispose();
s->handleSegFault(0);
2008-04-13 18:15:04 +00:00
allocator->free(this, sizeof(*this));
}
2008-04-09 19:08:13 +00:00
virtual object getStackTrace(Thread* vmt, Thread* vmTarget) {
MyThread* t = static_cast<MyThread*>(vmt);
MyThread* target = static_cast<MyThread*>(vmTarget);
MyProcessor* p = processor(t);
2008-04-09 19:08:13 +00:00
class Visitor: public System::ThreadVisitor {
public:
Visitor(MyThread* t, MyProcessor* p, MyThread* target):
t(t), p(p), target(target)
{ }
2008-04-09 19:08:13 +00:00
virtual void visit(void* ip, void* base, void* stack) {
void* oldIp = target->ip;
void* oldBase = target->base;
2008-04-09 19:08:13 +00:00
void* oldStack = target->stack;
if (methodForIp(t, ip)) {
target->ip = ip;
target->base = base;
target->stack = stack;
} else {
uint8_t* thunkStart = reinterpret_cast<uint8_t*>
(&singletonValue(t, p->thunkTable, 0));
uint8_t* thunkEnd = thunkStart + (p->thunkSize * ThunkCount);
if (static_cast<uint8_t*>(ip) >= thunkStart
and static_cast<uint8_t*>(ip) < thunkEnd)
{
2008-04-23 16:33:31 +00:00
target->ip = *static_cast<void**>(stack);
target->base = base;
target->stack = stack;
}
}
2008-04-09 19:08:13 +00:00
ensure(t, traceSize(target));
t->tracing = true;
2008-04-09 19:08:13 +00:00
trace = makeTrace(t, target);
t->tracing = false;
2008-04-09 19:08:13 +00:00
target->ip = oldIp;
target->base = oldBase;
target->stack = oldStack;
}
MyThread* t;
MyProcessor* p;
2008-04-09 19:08:13 +00:00
MyThread* target;
object trace;
} visitor(t, p, target);
2008-04-09 19:08:13 +00:00
t->m->system->visit(t->systemThread, target->systemThread, &visitor);
2008-04-09 19:08:13 +00:00
if (t->backupHeap) {
PROTECT(t, visitor.trace);
collect(t, Heap::MinorCollection);
}
return visitor.trace;
}
System* s;
Allocator* allocator;
object defaultThunk;
object nativeThunk;
object aioobThunk;
object thunkTable;
unsigned thunkSize;
object callTable;
unsigned callTableSize;
object methodTree;
object methodTreeSentinal;
2007-12-30 22:24:48 +00:00
SegFaultHandler segFaultHandler;
2008-04-13 18:15:04 +00:00
CodeAllocator codeAllocator;
Zone codeZone;
};
intptr_t
getThunk(MyThread* t, Thunk thunk)
{
MyProcessor* p = processor(t);
return reinterpret_cast<intptr_t>
(&singletonValue(t, p->thunkTable, (thunk * p->thunkSize) / BytesPerWord));
}
void
compileThunks(MyThread* t, MyProcessor* p)
{
class ThunkContext {
public:
class MyPromise: public Promise {
public:
MyPromise(): resolved_(false) { }
virtual int64_t value() {
return value_;
}
virtual bool resolved() {
return resolved_;
}
int64_t value_;
bool resolved_;
};
ThunkContext(MyThread* t): context(t) { }
Context context;
MyPromise promise;
};
ThunkContext defaultContext(t);
{ Assembler* a = defaultContext.context.assembler;
2008-08-16 17:45:36 +00:00
saveFrame(t, a);
pushFrame(t, a, 1);
setThreadArgument(t, a);
defaultContext.promise.resolved_ = true;
defaultContext.promise.value_ = reinterpret_cast<intptr_t>(compileMethod);
Assembler::Constant proc(&(defaultContext.promise));
a->apply(LongCall, BytesPerWord, ConstantOperand, &proc);
2008-08-16 17:45:36 +00:00
a->apply(PopFrame);
Assembler::Register result(a->returnLow());
a->apply(Jump, BytesPerWord, RegisterOperand, &result);
}
ThunkContext nativeContext(t);
{ Assembler* a = nativeContext.context.assembler;
2008-08-16 17:45:36 +00:00
saveFrame(t, a);
pushFrame(t, a, 1);
setThreadArgument(t, a);
nativeContext.promise.resolved_ = true;
nativeContext.promise.value_ = reinterpret_cast<intptr_t>(invokeNative);
Assembler::Constant proc(&(nativeContext.promise));
a->apply(LongCall, BytesPerWord, ConstantOperand, &proc);
2008-08-16 17:45:36 +00:00
a->apply(PopFrame);
a->apply(Return);
}
ThunkContext aioobContext(t);
{ Assembler* a = aioobContext.context.assembler;
2008-08-16 17:45:36 +00:00
saveFrame(t, a);
pushFrame(t, a, 1);
setThreadArgument(t, a);
aioobContext.promise.resolved_ = true;
aioobContext.promise.value_ = reinterpret_cast<intptr_t>
(throwArrayIndexOutOfBounds);
Assembler::Constant proc(&(aioobContext.promise));
a->apply(LongCall, BytesPerWord, ConstantOperand, &proc);
}
ThunkContext tableContext(t);
{ Assembler* a = tableContext.context.assembler;
2008-08-16 17:45:36 +00:00
saveFrame(t, a);
Assembler::Constant proc(&(tableContext.promise));
a->apply(LongJump, BytesPerWord, ConstantOperand, &proc);
}
p->thunkSize = pad(tableContext.context.assembler->length());
expect(t, codeZone(t)->ensure
(codeSingletonSizeInBytes
(t, defaultContext.context.assembler->length())
+ codeSingletonSizeInBytes
(t, nativeContext.context.assembler->length())
+ codeSingletonSizeInBytes
(t, aioobContext.context.assembler->length())
+ codeSingletonSizeInBytes
(t, p->thunkSize * ThunkCount)));
p->defaultThunk = finish(t, defaultContext.context.assembler, "default");
p->nativeThunk = finish(t, nativeContext.context.assembler, "native");
p->aioobThunk = finish(t, aioobContext.context.assembler, "aioob");
p->thunkTable = allocateCode(t, p->thunkSize * ThunkCount);
uint8_t* start = reinterpret_cast<uint8_t*>
(&singletonValue(t, p->thunkTable, 0));
if (Verbose) {
logCompile(start, p->thunkSize * ThunkCount, 0, "thunkTable", 0);
fprintf(stderr, "thunk size: %d\n", p->thunkSize);
}
tableContext.promise.resolved_ = true;
#define THUNK(s) \
tableContext.promise.value_ = reinterpret_cast<intptr_t>(s); \
tableContext.context.assembler->writeTo(start); \
start += p->thunkSize;
#include "thunks.cpp"
#undef THUNK
}
2007-12-09 22:45:43 +00:00
MyProcessor*
processor(MyThread* t)
2007-10-04 03:19:39 +00:00
{
2007-12-09 22:45:43 +00:00
MyProcessor* p = static_cast<MyProcessor*>(t->m->processor);
if (p->callTable == 0) {
2007-12-09 22:45:43 +00:00
ACQUIRE(t, t->m->classLock);
2007-10-04 03:19:39 +00:00
if (p->callTable == 0) {
p->callTable = makeArray(t, 128, true);
p->methodTree = p->methodTreeSentinal = makeTreeNode(t, 0, 0, 0);
set(t, p->methodTree, TreeNodeLeft, p->methodTreeSentinal);
set(t, p->methodTree, TreeNodeRight, p->methodTreeSentinal);
compileThunks(t, p);
2007-12-30 22:24:48 +00:00
p->segFaultHandler.m = t->m;
expect(t, t->m->system->success
(t->m->system->handleSegFault(&(p->segFaultHandler))));
}
2007-12-09 22:45:43 +00:00
}
return p;
}
2008-04-09 19:08:13 +00:00
object
defaultThunk(MyThread* t)
{
return processor(t)->defaultThunk;
}
object
nativeThunk(MyThread* t)
2008-04-09 19:08:13 +00:00
{
return processor(t)->nativeThunk;
2008-04-09 19:08:13 +00:00
}
object
aioobThunk(MyThread* t)
2008-04-09 19:08:13 +00:00
{
return processor(t)->aioobThunk;
2008-04-09 19:08:13 +00:00
}
void
2007-12-09 22:45:43 +00:00
compile(MyThread* t, object method)
{
MyProcessor* p = processor(t);
if (methodCompiled(t, method) == p->defaultThunk) {
2007-12-09 22:45:43 +00:00
PROTECT(t, method);
ACQUIRE(t, t->m->classLock);
if (methodCompiled(t, method) == p->defaultThunk) {
2008-01-08 19:36:34 +00:00
initClass(t, methodClass(t, method));
if (UNLIKELY(t->exception)) return;
if (methodCompiled(t, method) == p->defaultThunk) {
object node;
object compiled;
if (methodFlags(t, method) & ACC_NATIVE) {
node = 0;
compiled = p->nativeThunk;
} else {
Context context(t, method);
compiled = compile(t, &context);
if (UNLIKELY(t->exception)) return;
PROTECT(t, compiled);
2008-01-08 19:36:34 +00:00
if (DebugMethodTree) {
fprintf(stderr, "insert method at %p\n",
&singletonValue(t, compiled, 0));
}
// We can't set the MethodCompiled field on the original
// method before it is placed into the method tree, since
// another thread might call the method, from which stack
// unwinding would fail (since there is not yet an entry in
// the method tree). However, we can't insert the original
// method into the tree before setting the MethodCompiled
// field on it since we rely on that field to determine its
// position in the tree. Therefore, we insert a clone in
// its place. Later, we'll replace the clone with the
// original to save memory.
object clone = makeMethod
(t, methodVmFlags(t, method),
methodReturnCode(t, method),
methodParameterCount(t, method),
methodParameterFootprint(t, method),
methodFlags(t, method),
methodOffset(t, method),
methodName(t, method),
methodSpec(t, method),
methodClass(t, method),
methodCode(t, method),
compiled);
node = makeTreeNode
(t, clone, methodTreeSentinal(t), methodTreeSentinal(t));
PROTECT(t, node);
methodTree(t) = treeInsertNode
(t, methodTree(t), reinterpret_cast<intptr_t>
(&singletonValue(t, compiled, 0)), node, methodTreeSentinal(t),
compareIpToMethodBounds);
}
set(t, method, MethodCompiled, compiled);
2007-12-09 22:45:43 +00:00
if (methodVirtual(t, method)) {
classVtable(t, methodClass(t, method), methodOffset(t, method))
= &singletonValue(t, compiled, 0);
}
if (node) {
set(t, node, TreeNodeValue, method);
}
2007-12-11 23:52:28 +00:00
}
2007-12-09 22:45:43 +00:00
}
}
}
object
findCallNode(MyThread* t, void* address)
{
if (DebugCallTable) {
fprintf(stderr, "find call node %p\n", address);
}
2007-12-09 22:45:43 +00:00
MyProcessor* p = processor(t);
object table = p->callTable;
2007-12-11 00:48:09 +00:00
intptr_t key = reinterpret_cast<intptr_t>(address);
unsigned index = static_cast<uintptr_t>(key)
& (arrayLength(t, table) - 1);
2007-12-11 00:48:09 +00:00
for (object n = arrayBody(t, table, index);
n; n = callNodeNext(t, n))
2007-12-11 00:48:09 +00:00
{
intptr_t k = callNodeAddress(t, n);
2007-12-11 00:48:09 +00:00
if (k == key) {
return n;
}
}
return 0;
2007-12-11 00:48:09 +00:00
}
object
resizeTable(MyThread* t, object oldTable, unsigned newLength)
{
PROTECT(t, oldTable);
object oldNode = 0;
PROTECT(t, oldNode);
2007-12-11 00:48:09 +00:00
object newTable = makeArray(t, newLength, true);
2008-01-02 01:07:12 +00:00
PROTECT(t, newTable);
2007-12-11 00:48:09 +00:00
for (unsigned i = 0; i < arrayLength(t, oldTable); ++i) {
for (oldNode = arrayBody(t, oldTable, i);
oldNode;
oldNode = callNodeNext(t, oldNode))
{
intptr_t k = callNodeAddress(t, oldNode);
2007-12-11 00:48:09 +00:00
unsigned index = k & (newLength - 1);
object newNode = makeCallNode
(t, callNodeAddress(t, oldNode),
callNodeTarget(t, oldNode),
callNodeVirtualCall(t, oldNode),
arrayBody(t, newTable, index));
set(t, newTable, ArrayBody + (index * BytesPerWord), newNode);
2007-12-11 00:48:09 +00:00
}
}
return newTable;
2007-12-09 22:45:43 +00:00
}
2007-12-09 22:45:43 +00:00
void
insertCallNode(MyThread* t, object node)
2007-12-09 22:45:43 +00:00
{
if (DebugCallTable) {
fprintf(stderr, "insert call node %p\n",
reinterpret_cast<void*>(callNodeAddress(t, node)));
}
2007-12-09 22:45:43 +00:00
MyProcessor* p = processor(t);
2007-12-11 21:26:59 +00:00
PROTECT(t, node);
2007-12-11 00:48:09 +00:00
++ p->callTableSize;
if (p->callTableSize >= arrayLength(t, p->callTable) * 2) {
p->callTable = resizeTable
(t, p->callTable, arrayLength(t, p->callTable) * 2);
}
intptr_t key = callNodeAddress(t, node);
unsigned index = static_cast<uintptr_t>(key)
& (arrayLength(t, p->callTable) - 1);
set(t, node, CallNodeNext, arrayBody(t, p->callTable, index));
set(t, p->callTable, ArrayBody + (index * BytesPerWord), node);
}
2007-12-11 00:48:09 +00:00
object&
methodTree(MyThread* t)
{
return processor(t)->methodTree;
}
object
methodTreeSentinal(MyThread* t)
{
return processor(t)->methodTreeSentinal;
}
Zone*
2008-04-13 18:15:04 +00:00
codeZone(MyThread* t) {
return &(processor(t)->codeZone);
}
2007-12-09 22:45:43 +00:00
} // namespace
namespace vm {
2007-09-25 23:53:11 +00:00
Processor*
makeProcessor(System* system, Allocator* allocator)
{
2008-04-13 18:15:04 +00:00
return new (allocator->allocate(sizeof(MyProcessor)))
MyProcessor(system, allocator);
}
} // namespace vm