mirror of
https://github.com/corda/corda.git
synced 2025-01-19 03:06:36 +00:00
refactor stack walking interface in processor.h and sketch stack walking implementation in compile2.cpp
This commit is contained in:
parent
856935acc2
commit
49ed41daa0
4
makefile
4
makefile
@ -28,7 +28,7 @@ src = src
|
||||
classpath = classpath
|
||||
test = test
|
||||
|
||||
input = $(test-build)/List.class
|
||||
input = $(test-build)/Exceptions.class
|
||||
|
||||
build-cxx = g++
|
||||
build-cc = gcc
|
||||
@ -105,7 +105,7 @@ ifeq ($(platform),windows)
|
||||
endif
|
||||
|
||||
ifeq ($(mode),debug)
|
||||
cflags += -O0 -g3 -DNDEBUG
|
||||
cflags += -O0 -g3
|
||||
endif
|
||||
ifeq ($(mode),stress)
|
||||
cflags += -O0 -g3 -DVM_STRESS
|
||||
|
@ -317,12 +317,28 @@ Java_java_lang_reflect_Method_getCaller(Thread* t, jclass)
|
||||
{
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
Processor* p = t->m->processor;
|
||||
uintptr_t frame = p->frameStart(t);
|
||||
frame = p->frameNext(t, frame);
|
||||
frame = p->frameNext(t, frame);
|
||||
class Visitor: public Processor::StackVisitor {
|
||||
public:
|
||||
Visitor(Thread* t): t(t), method(0), count(0) { }
|
||||
|
||||
return makeLocalReference(t, p->frameMethod(t, frame));
|
||||
virtual bool visit(Processor::StackWalker* walker) {
|
||||
if (count == 2) {
|
||||
method = walker->method();
|
||||
return false;
|
||||
} else {
|
||||
++ count;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Thread* t;
|
||||
object method;
|
||||
unsigned count;
|
||||
} v(t);
|
||||
|
||||
t->m->processor->walkStack(t, &v);
|
||||
|
||||
return makeLocalReference(t, v.method);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jobject JNICALL
|
||||
@ -567,27 +583,41 @@ Java_java_lang_Throwable_trace(Thread* t, jclass, jint skipCount)
|
||||
{
|
||||
ENTER(t, Thread::ActiveState);
|
||||
|
||||
Processor* p = t->m->processor;
|
||||
uintptr_t frame = p->frameStart(t);
|
||||
class Visitor: public Processor::StackVisitor {
|
||||
public:
|
||||
Visitor(Thread* t, int skipCount):
|
||||
t(t), trace(0), skipCount(skipCount)
|
||||
{ }
|
||||
|
||||
while (skipCount-- and p->frameValid(t, frame)) {
|
||||
frame = p->frameNext(t, frame);
|
||||
}
|
||||
|
||||
// skip Throwable constructors
|
||||
while (p->frameValid(t, frame)
|
||||
and isAssignableFrom
|
||||
(t, arrayBody(t, t->m->types, Machine::ThrowableType),
|
||||
methodClass(t, p->frameMethod(t, frame)))
|
||||
and strcmp(reinterpret_cast<const int8_t*>("<init>"),
|
||||
&byteArrayBody
|
||||
(t, methodName(t, p->frameMethod(t, frame)), 0))
|
||||
== 0)
|
||||
{
|
||||
frame = p->frameNext(t, frame);
|
||||
}
|
||||
virtual bool visit(Processor::StackWalker* walker) {
|
||||
if (skipCount == 0) {
|
||||
object method = walker->method();
|
||||
if (isAssignableFrom
|
||||
(t, arrayBody(t, t->m->types, Machine::ThrowableType),
|
||||
methodClass(t, method))
|
||||
and strcmp(reinterpret_cast<const int8_t*>("<init>"),
|
||||
&byteArrayBody(t, methodName(t, method), 0))
|
||||
== 0)
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
trace = makeTrace(t, walker);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
-- skipCount;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return makeLocalReference(t, makeTrace(t, frame));
|
||||
Thread* t;
|
||||
object trace;
|
||||
unsigned skipCount;
|
||||
} v(t, skipCount);
|
||||
|
||||
t->m->processor->walkStack(t, &v);
|
||||
|
||||
return makeLocalReference(t, v.trace);
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jarray JNICALL
|
||||
|
@ -239,6 +239,12 @@ bitsToFloat(uint32_t bits)
|
||||
return f;
|
||||
}
|
||||
|
||||
inline intptr_t
|
||||
difference(void* a, void* b)
|
||||
{
|
||||
return reinterpret_cast<intptr_t>(a) - reinterpret_cast<intptr_t>(b);
|
||||
}
|
||||
|
||||
class Machine;
|
||||
class Thread;
|
||||
|
||||
|
566
src/compile2.cpp
566
src/compile2.cpp
@ -19,16 +19,196 @@ namespace {
|
||||
|
||||
class MyThread: public Thread {
|
||||
public:
|
||||
class CallTrace {
|
||||
public:
|
||||
CallTrace(MyThread* t):
|
||||
t(t),
|
||||
base(t->base),
|
||||
stack(t->stack),
|
||||
next(t->trace)
|
||||
{
|
||||
t->trace = this;
|
||||
t->base = 0;
|
||||
t->stack = 0;
|
||||
}
|
||||
|
||||
~CallTrace() {
|
||||
t->stack = stack;
|
||||
t->base = base;
|
||||
t->trace = next;
|
||||
}
|
||||
|
||||
MyThread* t;
|
||||
void* base;
|
||||
void* stack;
|
||||
CallTrace* next;
|
||||
};
|
||||
|
||||
MyThread(Machine* m, object javaThread, Thread* parent):
|
||||
Thread(m, javaThread, parent),
|
||||
caller(0),
|
||||
base(0),
|
||||
stack(0),
|
||||
trace(0),
|
||||
reference(0)
|
||||
{ }
|
||||
|
||||
void* caller;
|
||||
void* base;
|
||||
void* stack;
|
||||
CallTrace* trace;
|
||||
Reference* reference;
|
||||
};
|
||||
|
||||
object
|
||||
resolveTarget(MyThread* t, void* stack, object method)
|
||||
{
|
||||
if (methodVirtual(t, method)) {
|
||||
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
||||
object class_ = objectClass
|
||||
(t, reinterpret_cast<object*>(stack)[parameterFootprint + 1]);
|
||||
|
||||
if (classVmFlags(t, class_) & BootstrapFlag) {
|
||||
resolveClass(t, className(t, class_));
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
}
|
||||
|
||||
if (classFlags(t, methodClass(t, method)) & ACC_INTERFACE) {
|
||||
return findInterfaceMethod(t, method, class_);
|
||||
} else {
|
||||
return findMethod(t, method, class_);
|
||||
}
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
object
|
||||
findTraceNode(MyThread* t, void* address);
|
||||
|
||||
class MyStackWalker: public Processor::StackWalker {
|
||||
public:
|
||||
class MyProtector: public Thread::Protector {
|
||||
public:
|
||||
MyProtector(MyStackWalker* walker):
|
||||
Protector(walker->t), walker(walker)
|
||||
{ }
|
||||
|
||||
virtual void visit(Heap::Visitor* v) {
|
||||
v->visit(&(walker->node));
|
||||
v->visit(&(walker->nativeMethod));
|
||||
}
|
||||
|
||||
MyStackWalker* walker;
|
||||
};
|
||||
|
||||
MyStackWalker(MyThread* t):
|
||||
t(t),
|
||||
base(t->base),
|
||||
stack(t->stack),
|
||||
trace(t->trace),
|
||||
node(findTraceNode(t, *static_cast<void**>(stack))),
|
||||
nativeMethod(resolveNativeMethod(t, stack, node)),
|
||||
protector(this)
|
||||
{ }
|
||||
|
||||
MyStackWalker(MyStackWalker* w):
|
||||
t(w->t),
|
||||
base(w->base),
|
||||
stack(w->stack),
|
||||
trace(w->trace),
|
||||
node(w->node),
|
||||
nativeMethod(w->nativeMethod),
|
||||
protector(this)
|
||||
{ }
|
||||
|
||||
static object resolveNativeMethod(MyThread* t, void* stack, object node) {
|
||||
if (node) {
|
||||
object target = resolveTarget(t, stack, traceNodeTarget(t, node));
|
||||
if (target and methodFlags(t, target) & ACC_NATIVE) {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void walk(Processor::StackVisitor* v) {
|
||||
if (not v->visit(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (MyStackWalker it(this); it.next();) {
|
||||
MyStackWalker walker(it);
|
||||
if (not v->visit(&walker)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool next() {
|
||||
if (nativeMethod) {
|
||||
nativeMethod = 0;
|
||||
} else {
|
||||
stack = static_cast<void**>(base) + 1;
|
||||
base = *static_cast<void**>(base);
|
||||
node = findTraceNode(t, *static_cast<void**>(stack));
|
||||
if (node == 0) {
|
||||
if (trace) {
|
||||
base = trace->base;
|
||||
stack = static_cast<void**>(trace->stack);
|
||||
trace = trace->next;
|
||||
node = findTraceNode(t, *static_cast<void**>(stack));
|
||||
nativeMethod = resolveNativeMethod(t, stack, node);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual object method() {
|
||||
if (nativeMethod) {
|
||||
return nativeMethod;
|
||||
} else {
|
||||
return traceNodeMethod(t, node);
|
||||
}
|
||||
}
|
||||
|
||||
virtual int ip() {
|
||||
if (nativeMethod) {
|
||||
return NativeLine;
|
||||
} else {
|
||||
return traceNodeLine(t, node);
|
||||
}
|
||||
}
|
||||
|
||||
virtual unsigned count() {
|
||||
class Visitor: public Processor::StackVisitor {
|
||||
public:
|
||||
Visitor(): count(0) { }
|
||||
|
||||
virtual bool visit(Processor::StackWalker*) {
|
||||
++ count;
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned count;
|
||||
} v;
|
||||
|
||||
MyStackWalker walker(this);
|
||||
walker.walk(&v);
|
||||
|
||||
return v.count;
|
||||
}
|
||||
|
||||
MyThread* t;
|
||||
void* base;
|
||||
void* stack;
|
||||
MyThread::CallTrace* trace;
|
||||
object node;
|
||||
object nativeMethod;
|
||||
MyProtector protector;
|
||||
};
|
||||
|
||||
uintptr_t*
|
||||
makeCodeMask(MyThread* t, unsigned length)
|
||||
{
|
||||
@ -162,12 +342,12 @@ class Frame {
|
||||
}
|
||||
|
||||
void storedInt(unsigned index) {
|
||||
assert(t, index < localSize());
|
||||
assert(t, index < localSize(t, method));
|
||||
clearBit(map, index);
|
||||
}
|
||||
|
||||
void storedObject(unsigned index) {
|
||||
assert(t, index < localSize());
|
||||
assert(t, index < localSize(t, method));
|
||||
markBit(map, index);
|
||||
}
|
||||
|
||||
@ -235,7 +415,7 @@ class Frame {
|
||||
|
||||
void dupped2() {
|
||||
assert(t, sp + 2 <= mapSize(t, method));
|
||||
assert(t, sp - 2 >= localSize());
|
||||
assert(t, sp - 2 >= localSize(t, method));
|
||||
|
||||
unsigned b2 = getBit(map, sp - 2);
|
||||
unsigned b1 = getBit(map, sp - 1);
|
||||
@ -356,7 +536,7 @@ class Frame {
|
||||
|
||||
void pop(unsigned count) {
|
||||
assert(t, sp >= count);
|
||||
assert(t, sp - count >= localSize());
|
||||
assert(t, sp - count >= localSize(t, method));
|
||||
while (count) {
|
||||
clearBit(map, -- sp);
|
||||
-- count;
|
||||
@ -418,20 +598,20 @@ class Frame {
|
||||
}
|
||||
|
||||
void loadInt(unsigned index) {
|
||||
assert(t, index < localSize());
|
||||
assert(t, index < localSize(t, method));
|
||||
assert(t, getBit(map, index) == 0);
|
||||
pushInt(c->memory(c->base(), localOffset(t, index, method)));
|
||||
}
|
||||
|
||||
void loadLong(unsigned index) {
|
||||
assert(t, index < localSize() - 1);
|
||||
assert(t, index < localSize(t, method) - 1);
|
||||
assert(t, getBit(map, index) == 0);
|
||||
assert(t, getBit(map, index + 1) == 0);
|
||||
pushLong(c->memory(c->base(), localOffset(t, index, method)));
|
||||
}
|
||||
|
||||
void loadObject(unsigned index) {
|
||||
assert(t, index < localSize());
|
||||
assert(t, index < localSize(t, method));
|
||||
assert(t, getBit(map, index) != 0);
|
||||
pushObject(c->memory(c->base(), localOffset(t, index, method)));
|
||||
}
|
||||
@ -453,7 +633,7 @@ class Frame {
|
||||
}
|
||||
|
||||
void increment(unsigned index, unsigned count) {
|
||||
assert(t, index < localSize());
|
||||
assert(t, index < localSize(t, method));
|
||||
assert(t, getBit(map, index) == 0);
|
||||
c->add(c->constant(count),
|
||||
c->memory(c->base(), localOffset(t, index, method)));
|
||||
@ -553,7 +733,38 @@ class Frame {
|
||||
};
|
||||
|
||||
void NO_RETURN
|
||||
unwind(MyThread* t);
|
||||
unwind(MyThread* t)
|
||||
{
|
||||
void* base = t->base;
|
||||
void** stack = static_cast<void**>(t->stack);
|
||||
while (true) {
|
||||
void* returnAddress = *stack;
|
||||
object node = findTraceNode(t, returnAddress);
|
||||
if (node) {
|
||||
void* handler = traceNodeHandler(t, node);
|
||||
if (handler) {
|
||||
object method = traceNodeMethod(t, node);
|
||||
|
||||
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
||||
unsigned localFootprint = codeMaxLocals(t, methodCode(t, method));
|
||||
|
||||
if (localFootprint > parameterFootprint) {
|
||||
stack -= (localFootprint - parameterFootprint);
|
||||
}
|
||||
|
||||
*(--stack) = t->exception;
|
||||
t->exception = 0;
|
||||
|
||||
vmJump(handler, base, stack);
|
||||
} else {
|
||||
stack = static_cast<void**>(base) + 1;
|
||||
base = *static_cast<void**>(base);
|
||||
}
|
||||
} else {
|
||||
vmJump(returnAddress, base, stack + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
findInterfaceMethodFromInstance(Thread* t, object method, object instance)
|
||||
@ -1140,8 +1351,9 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
break;
|
||||
|
||||
case athrow:
|
||||
c->indirectCallNoReturn(c->constant(reinterpret_cast<intptr_t>(throw_)),
|
||||
2, c->thread(), frame->popObject());
|
||||
c->indirectCallNoReturn
|
||||
(c->constant(reinterpret_cast<intptr_t>(throw_)),
|
||||
2, c->thread(), frame->popObject());
|
||||
break;
|
||||
|
||||
case bipush:
|
||||
@ -1451,7 +1663,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
} break;
|
||||
|
||||
case goto_: {
|
||||
int32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
c->jmp(c->logicalIp(newIp));
|
||||
@ -1459,7 +1671,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
} break;
|
||||
|
||||
case goto_w: {
|
||||
int32_t newIp = (ip - 5) + codeReadInt32(t, code, ip);
|
||||
uint32_t newIp = (ip - 5) + codeReadInt32(t, code, ip);
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
c->jmp(c->logicalIp(newIp));
|
||||
@ -1544,7 +1756,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
|
||||
case if_acmpeq:
|
||||
case if_acmpne: {
|
||||
int32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
Operand* a = frame->popObject();
|
||||
@ -1568,7 +1780,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
case if_icmpge:
|
||||
case if_icmplt:
|
||||
case if_icmple: {
|
||||
int32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
Operand* a = frame->popInt();
|
||||
@ -1607,7 +1819,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
case ifge:
|
||||
case iflt:
|
||||
case ifle: {
|
||||
int32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
c->cmp(0, frame->popInt());
|
||||
@ -1640,7 +1852,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
|
||||
case ifnull:
|
||||
case ifnonnull: {
|
||||
int32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
uint32_t newIp = (ip - 3) + codeReadInt16(t, code, ip);
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
c->cmp(0, frame->popObject());
|
||||
@ -2022,7 +2234,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
|
||||
Operand* key = frame->popInt();
|
||||
|
||||
int32_t defaultIp = base + codeReadInt32(t, code, ip);
|
||||
uint32_t defaultIp = base + codeReadInt32(t, code, ip);
|
||||
assert(t, defaultIp < codeLength(t, code));
|
||||
|
||||
compile(t, frame, defaultIp);
|
||||
@ -2036,7 +2248,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
for (int32_t i = 0; i < pairCount; ++i) {
|
||||
unsigned index = ip + (i * 8);
|
||||
int32_t key = codeReadInt32(t, code, index);
|
||||
int32_t newIp = base + codeReadInt32(t, code, index);
|
||||
uint32_t newIp = base + codeReadInt32(t, code, index);
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
compile(t, frame, newIp);
|
||||
@ -2341,7 +2553,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
|
||||
Operand* key = frame->popInt();
|
||||
|
||||
int32_t defaultIp = base + codeReadInt32(t, code, ip);
|
||||
uint32_t defaultIp = base + codeReadInt32(t, code, ip);
|
||||
assert(t, defaultIp < codeLength(t, code));
|
||||
|
||||
compile(t, frame, defaultIp);
|
||||
@ -2355,7 +2567,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
Operand* start;
|
||||
for (int32_t i = 0; i < bottom - top + 1; ++i) {
|
||||
unsigned index = ip + (i * 4);
|
||||
int32_t newIp = base + codeReadInt32(t, code, index);
|
||||
uint32_t newIp = base + codeReadInt32(t, code, index);
|
||||
assert(t, newIp < codeLength(t, code));
|
||||
|
||||
compile(t, frame, newIp);
|
||||
@ -2478,7 +2690,7 @@ compile(MyThread* t, Compiler* c, object method)
|
||||
for (unsigned i = 0; i < exceptionHandlerTableLength(t, eht); ++i) {
|
||||
ExceptionHandler* eh = exceptionHandlerTableBody(t, eht, i);
|
||||
|
||||
assert(t, getBit(codeMask, exceptionHandlerStart(eh)));
|
||||
assert(t, getBit(frame.codeMask, exceptionHandlerStart(eh)));
|
||||
|
||||
uintptr_t map[Frame::mapSizeInWords(t, method)];
|
||||
Frame frame2(&frame, map);
|
||||
@ -2496,24 +2708,258 @@ void
|
||||
compile(MyThread* t, object method);
|
||||
|
||||
void*
|
||||
compileMethod(MyThread* t);
|
||||
compileMethod(MyThread* t)
|
||||
{
|
||||
object node = findTraceNode(t, *static_cast<void**>(t->stack));
|
||||
object target = resolveTarget(t, t->stack, traceNodeTarget(t, node));
|
||||
|
||||
void*
|
||||
invokeNative(MyThread* t);
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
compile(t, target);
|
||||
}
|
||||
|
||||
if (UNLIKELY(t->exception)) {
|
||||
unwind(t);
|
||||
} else {
|
||||
return &singletonValue(t, methodCompiled(t, target), 0);
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
invokeNative2(MyThread* t, object method)
|
||||
{
|
||||
PROTECT(t, method);
|
||||
|
||||
if (objectClass(t, methodCode(t, method))
|
||||
== arrayBody(t, t->m->types, Machine::ByteArrayType))
|
||||
{
|
||||
void* function = resolveNativeMethod(t, method);
|
||||
if (UNLIKELY(function == 0)) {
|
||||
object message = makeString
|
||||
(t, "%s", &byteArrayBody(t, methodCode(t, method), 0));
|
||||
t->exception = makeUnsatisfiedLinkError(t, message);
|
||||
return 0;
|
||||
}
|
||||
|
||||
object p = makePointer(t, function);
|
||||
set(t, method, MethodCode, p);
|
||||
}
|
||||
|
||||
object class_ = methodClass(t, method);
|
||||
PROTECT(t, class_);
|
||||
|
||||
unsigned footprint = methodParameterFootprint(t, method) + 1;
|
||||
unsigned count = methodParameterCount(t, method) + 1;
|
||||
if (methodFlags(t, method) & ACC_STATIC) {
|
||||
++ footprint;
|
||||
++ count;
|
||||
}
|
||||
|
||||
uintptr_t args[footprint];
|
||||
unsigned argOffset = 0;
|
||||
uint8_t types[count];
|
||||
unsigned typeOffset = 0;
|
||||
|
||||
args[argOffset++] = reinterpret_cast<uintptr_t>(t);
|
||||
types[typeOffset++] = POINTER_TYPE;
|
||||
|
||||
uintptr_t* sp = static_cast<uintptr_t*>(t->stack)
|
||||
+ (methodParameterFootprint(t, method) + 1);
|
||||
|
||||
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;
|
||||
|
||||
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()));
|
||||
|
||||
switch (type) {
|
||||
case INT8_TYPE:
|
||||
case INT16_TYPE:
|
||||
case INT32_TYPE:
|
||||
case FLOAT_TYPE:
|
||||
args[argOffset++] = *(sp--);
|
||||
break;
|
||||
|
||||
case INT64_TYPE:
|
||||
case DOUBLE_TYPE: {
|
||||
if (BytesPerWord == 8) {
|
||||
uint64_t a = *(sp--);
|
||||
uint64_t b = *(sp--);
|
||||
args[argOffset++] = (a << 32) | b;
|
||||
} else {
|
||||
memcpy(args + argOffset, sp, 8);
|
||||
argOffset += 2;
|
||||
sp -= 2;
|
||||
}
|
||||
} break;
|
||||
|
||||
case POINTER_TYPE: {
|
||||
args[argOffset++] = reinterpret_cast<uintptr_t>(sp--);
|
||||
} break;
|
||||
|
||||
default: abort(t);
|
||||
}
|
||||
}
|
||||
|
||||
void* function = pointerValue(t, methodCode(t, method));
|
||||
unsigned returnType = fieldType(t, methodReturnCode(t, method));
|
||||
uint64_t result;
|
||||
|
||||
if (Verbose) {
|
||||
fprintf(stderr, "invoke native method %s.%s\n",
|
||||
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
|
||||
&byteArrayBody(t, methodName(t, method), 0));
|
||||
}
|
||||
|
||||
{ ENTER(t, Thread::IdleState);
|
||||
|
||||
result = t->m->system->call
|
||||
(function,
|
||||
args,
|
||||
types,
|
||||
count + 1,
|
||||
footprint * BytesPerWord,
|
||||
returnType);
|
||||
}
|
||||
|
||||
if (Verbose) {
|
||||
fprintf(stderr, "return from native method %s.%s\n",
|
||||
&byteArrayBody(t, className(t, methodClass(t, method)), 0),
|
||||
&byteArrayBody(t, methodName(t, method), 0));
|
||||
}
|
||||
|
||||
if (LIKELY(t->exception == 0) and returnType == POINTER_TYPE) {
|
||||
return result ? *reinterpret_cast<uintptr_t*>(result) : 0;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t
|
||||
invokeNative(MyThread* t)
|
||||
{
|
||||
object node = findTraceNode(t, *static_cast<void**>(t->stack));
|
||||
object target = resolveTarget(t, t->stack, traceNodeTarget(t, node));
|
||||
uint64_t result;
|
||||
|
||||
if (LIKELY(t->exception == 0)) {
|
||||
result = invokeNative2(t, target);
|
||||
}
|
||||
|
||||
if (UNLIKELY(t->exception)) {
|
||||
unwind(t);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
inline object*
|
||||
localObject(MyThread* t, void* base, object method, unsigned index)
|
||||
{
|
||||
return reinterpret_cast<object*>
|
||||
(static_cast<uint8_t*>(base) + localOffset(t, index, method));
|
||||
}
|
||||
|
||||
void
|
||||
visitStack(MyThread* t, Heap::Visitor* v);
|
||||
visitParameters(MyThread* t, Heap::Visitor* v, void* base, object method)
|
||||
{
|
||||
const char* spec = reinterpret_cast<const char*>
|
||||
(&byteArrayBody(t, methodSpec(t, method), 0));
|
||||
|
||||
unsigned index = 0;
|
||||
if ((methodFlags(t, method) & ACC_STATIC) == 0) {
|
||||
v->visit(localObject(t, base, method, index++));
|
||||
}
|
||||
|
||||
for (MethodSpecIterator it(t, spec); it.hasNext();) {
|
||||
switch (*it.next()) {
|
||||
case 'L':
|
||||
case '[':
|
||||
v->visit(localObject(t, base, method, index++));
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
case 'D':
|
||||
index += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
++ index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(t, index == methodParameterFootprint(t, method));
|
||||
}
|
||||
|
||||
void
|
||||
visitStackAndLocals(MyThread* t, Heap::Visitor* v, void* base, object node)
|
||||
{
|
||||
object method = traceNodeMethod(t, node);
|
||||
|
||||
unsigned parameterFootprint = methodParameterFootprint(t, method);
|
||||
unsigned count = codeMaxStack(t, methodCode(t, method))
|
||||
+ codeMaxLocals(t, methodCode(t, method))
|
||||
- parameterFootprint;
|
||||
|
||||
if (count) {
|
||||
uintptr_t* map = &traceNodeMap(t, node, 0);
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
if (getBit(map, i)) {
|
||||
v->visit(localObject(t, base, method, i + parameterFootprint));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
visitStack(MyThread* t, Heap::Visitor* v)
|
||||
{
|
||||
void* base = t->base;
|
||||
void** stack = static_cast<void**>(t->stack);
|
||||
MyThread::CallTrace* trace = t->trace;
|
||||
while (true) {
|
||||
object node = findTraceNode(t, *stack);
|
||||
if (node) {
|
||||
object method = traceNodeMethod(t, node);
|
||||
|
||||
// we only need to visit the parameters of this method if the
|
||||
// caller is native. Otherwise, the caller owns them.
|
||||
object next = findTraceNode(t, static_cast<void**>(base)[1]);
|
||||
if (next == 0) {
|
||||
visitParameters(t, v, base, method);
|
||||
}
|
||||
|
||||
visitStackAndLocals(t, v, base, method);
|
||||
|
||||
stack = static_cast<void**>(base) + 1;
|
||||
base = *static_cast<void**>(base);
|
||||
} else if (trace) {
|
||||
base = trace->base;
|
||||
stack = static_cast<void**>(trace->stack);
|
||||
trace = trace->next;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
compileDefault(MyThread* t, Compiler* c)
|
||||
{
|
||||
c->prologue();
|
||||
|
||||
unsigned caller
|
||||
= reinterpret_cast<uintptr_t>(&(t->caller))
|
||||
- reinterpret_cast<uintptr_t>(t);
|
||||
|
||||
c->mov(c->base(), c->memory(c->thread(), caller));
|
||||
c->mov(c->base(), c->memory(c->thread(), difference(&(t->base), t)));
|
||||
c->mov(c->stack(), c->memory(c->thread(), difference(&(t->stack), t)));
|
||||
|
||||
c->epilogue();
|
||||
|
||||
@ -2530,11 +2976,8 @@ compileNative(MyThread* t, Compiler* c)
|
||||
{
|
||||
c->prologue();
|
||||
|
||||
unsigned caller
|
||||
= reinterpret_cast<uintptr_t>(&(t->caller))
|
||||
- reinterpret_cast<uintptr_t>(t);
|
||||
|
||||
c->mov(c->base(), c->memory(c->thread(), caller));
|
||||
c->mov(c->base(), c->memory(c->thread(), difference(&(t->base), t)));
|
||||
c->mov(c->stack(), c->memory(c->thread(), difference(&(t->stack), t)));
|
||||
|
||||
c->call
|
||||
(c->directCall
|
||||
@ -2668,14 +3111,12 @@ invoke(Thread* thread, object method, ArgumentList* arguments)
|
||||
unsigned returnType = fieldType(t, returnCode);
|
||||
|
||||
Reference* reference = t->reference;
|
||||
void* caller = t->caller;
|
||||
MyThread::CallTrace trace(t);
|
||||
|
||||
uint64_t result = vmInvoke
|
||||
(t, &singletonValue(t, methodCompiled(t, method), 0), arguments->array,
|
||||
arguments->position * BytesPerWord, returnType);
|
||||
|
||||
t->caller = caller;
|
||||
|
||||
while (t->reference != reference) {
|
||||
dispose(t, t->reference);
|
||||
}
|
||||
@ -2843,40 +3284,19 @@ class MyProcessor: public Processor {
|
||||
visitStack(t, v);
|
||||
}
|
||||
|
||||
virtual uintptr_t
|
||||
frameStart(Thread* t)
|
||||
virtual void
|
||||
walkStack(Thread* vmt, StackVisitor* v)
|
||||
{
|
||||
abort(t);
|
||||
}
|
||||
MyThread* t = static_cast<MyThread*>(vmt);
|
||||
|
||||
virtual uintptr_t
|
||||
frameNext(Thread* t, uintptr_t)
|
||||
{
|
||||
abort(t);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
frameValid(Thread* t, uintptr_t)
|
||||
{
|
||||
abort(t);
|
||||
}
|
||||
|
||||
virtual object
|
||||
frameMethod(Thread* t, uintptr_t)
|
||||
{
|
||||
abort(t);
|
||||
}
|
||||
|
||||
virtual unsigned
|
||||
frameIp(Thread* t, uintptr_t)
|
||||
{
|
||||
abort(t);
|
||||
MyStackWalker walker(t);
|
||||
walker.walk(v);
|
||||
}
|
||||
|
||||
virtual int
|
||||
lineNumber(Thread* t, object, unsigned)
|
||||
lineNumber(Thread*, object, int ip)
|
||||
{
|
||||
abort(t);
|
||||
return ip;
|
||||
}
|
||||
|
||||
virtual object*
|
||||
@ -3017,12 +3437,10 @@ compile(MyThread* t, object method)
|
||||
if (methodCompiled(t, method) == stub) {
|
||||
if (p->indirectCaller == 0) {
|
||||
Compiler* c = makeCompiler(t->m->system, 0);
|
||||
|
||||
unsigned caller
|
||||
= reinterpret_cast<uintptr_t>(&(t->caller))
|
||||
- reinterpret_cast<uintptr_t>(t);
|
||||
|
||||
c->mov(c->base(), c->memory(c->thread(), caller));
|
||||
c->mov(c->base(), c->memory(c->thread(), difference(&(t->base), t)));
|
||||
c->mov(c->stack(), c->memory(c->thread(), difference(&(t->stack), t)));
|
||||
|
||||
c->jmp(c->indirectTarget());
|
||||
|
||||
p->indirectCaller = t->m->system->allocate(c->size());
|
||||
|
@ -19,7 +19,6 @@ class Compiler {
|
||||
|
||||
virtual void push(Operand*) = 0;
|
||||
virtual void push2(Operand*) = 0;
|
||||
virtual Operand* stack() = 0;
|
||||
virtual Operand* stack(unsigned) = 0;
|
||||
virtual Operand* stack2(unsigned) = 0;
|
||||
virtual Operand* pop() = 0;
|
||||
@ -27,10 +26,10 @@ class Compiler {
|
||||
virtual void pop(Operand*) = 0;
|
||||
virtual void pop2(Operand*) = 0;
|
||||
|
||||
virtual Operand* stack() = 0;
|
||||
virtual Operand* base() = 0;
|
||||
virtual Operand* thread() = 0;
|
||||
virtual Operand* indirectTarget() = 0;
|
||||
|
||||
virtual Operand* temporary() = 0;
|
||||
virtual void release(Operand*) = 0;
|
||||
|
||||
|
@ -35,6 +35,44 @@ class Thread: public vm::Thread {
|
||||
uintptr_t stack[StackSizeInWords];
|
||||
};
|
||||
|
||||
int
|
||||
lineNumber(Thread* t, object method, unsigned ip)
|
||||
{
|
||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||
return NativeLine;
|
||||
}
|
||||
|
||||
// our parameter indicates the instruction following the one we care
|
||||
// about, so we back up first:
|
||||
-- ip;
|
||||
|
||||
object code = methodCode(t, method);
|
||||
object lnt = codeLineNumberTable(t, code);
|
||||
if (lnt) {
|
||||
unsigned bottom = 0;
|
||||
unsigned top = lineNumberTableLength(t, lnt);
|
||||
for (unsigned span = top - bottom; span; span = top - bottom) {
|
||||
unsigned middle = bottom + (span / 2);
|
||||
LineNumber* ln = lineNumberTableBody(t, lnt, middle);
|
||||
|
||||
if (ip >= lineNumberIp(ln)
|
||||
and (middle + 1 == lineNumberTableLength(t, lnt)
|
||||
or ip < lineNumberIp(lineNumberTableBody(t, lnt, middle + 1))))
|
||||
{
|
||||
return lineNumberLine(ln);
|
||||
} else if (ip < lineNumberIp(ln)) {
|
||||
top = middle;
|
||||
} else if (ip > lineNumberIp(ln)) {
|
||||
bottom = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
abort(t);
|
||||
} else {
|
||||
return UnknownLine;
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
pushObject(Thread* t, object o)
|
||||
{
|
||||
@ -356,6 +394,39 @@ popFrame(Thread* t)
|
||||
}
|
||||
}
|
||||
|
||||
class MyStackWalker: public Processor::StackWalker {
|
||||
public:
|
||||
MyStackWalker(Thread* t, int frame): t(t), frame(frame) { }
|
||||
|
||||
virtual void walk(Processor::StackVisitor* v) {
|
||||
for (int frame = this->frame; frame >= 0; frame = frameNext(t, frame)) {
|
||||
MyStackWalker walker(t, frame);
|
||||
if (not v->visit(&walker)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual object method() {
|
||||
return frameMethod(t, frame);
|
||||
}
|
||||
|
||||
virtual int ip() {
|
||||
return frameIp(t, frame);
|
||||
}
|
||||
|
||||
virtual unsigned count() {
|
||||
unsigned count = 0;
|
||||
for (int frame = this->frame; frame >= 0; frame = frameNext(t, frame)) {
|
||||
++ count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
Thread* t;
|
||||
int frame;
|
||||
};
|
||||
|
||||
object
|
||||
makeNativeMethodData(Thread* t, object method, void* function)
|
||||
{
|
||||
@ -768,7 +839,7 @@ interpret(Thread* t)
|
||||
&byteArrayBody
|
||||
(t, methodName(t, frameMethod(t, frame)), 0));
|
||||
|
||||
int line = t->m->processor->lineNumber(t, frameMethod(t, frame), ip);
|
||||
int line = lineNumber(t, frameMethod(t, frame), ip);
|
||||
switch (line) {
|
||||
case NativeLine:
|
||||
fprintf(stderr, "(native)\n");
|
||||
@ -2900,74 +2971,23 @@ class MyProcessor: public Processor {
|
||||
}
|
||||
}
|
||||
|
||||
virtual uintptr_t
|
||||
frameStart(vm::Thread* vmt)
|
||||
virtual void
|
||||
walkStack(vm::Thread* vmt, StackVisitor* v)
|
||||
{
|
||||
Thread* t = static_cast<Thread*>(vmt);
|
||||
|
||||
if (t->frame >= 0) {
|
||||
pokeInt(t, t->frame + FrameIpOffset, t->ip);
|
||||
}
|
||||
return t->frame;
|
||||
}
|
||||
|
||||
virtual uintptr_t
|
||||
frameNext(vm::Thread* vmt, uintptr_t frame)
|
||||
{
|
||||
Thread* t = static_cast<Thread*>(vmt);
|
||||
|
||||
assert(t, static_cast<intptr_t>(frame) >= 0);
|
||||
return ::frameNext(t, frame);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
frameValid(vm::Thread*, uintptr_t frame)
|
||||
{
|
||||
return static_cast<intptr_t>(frame) >= 0;
|
||||
}
|
||||
|
||||
virtual object
|
||||
frameMethod(vm::Thread* vmt, uintptr_t frame)
|
||||
{
|
||||
Thread* t = static_cast<Thread*>(vmt);
|
||||
|
||||
assert(t, static_cast<intptr_t>(frame) >= 0);
|
||||
return ::frameMethod(t, frame);
|
||||
}
|
||||
|
||||
virtual unsigned
|
||||
frameIp(vm::Thread* vmt, uintptr_t frame)
|
||||
{
|
||||
Thread* t = static_cast<Thread*>(vmt);
|
||||
|
||||
assert(t, static_cast<intptr_t>(frame) >= 0);
|
||||
return ::frameIp(t, frame);
|
||||
MyStackWalker walker(t, t->frame);
|
||||
walker.walk(v);
|
||||
}
|
||||
|
||||
virtual int
|
||||
lineNumber(vm::Thread* vmt, object method, unsigned ip)
|
||||
lineNumber(vm::Thread* t, object method, int ip)
|
||||
{
|
||||
Thread* t = static_cast<Thread*>(vmt);
|
||||
|
||||
if (methodFlags(t, method) & ACC_NATIVE) {
|
||||
return NativeLine;
|
||||
}
|
||||
|
||||
object table = codeLineNumberTable(t, methodCode(t, method));
|
||||
if (table) {
|
||||
// todo: do a binary search:
|
||||
int last = UnknownLine;
|
||||
for (unsigned i = 0; i < lineNumberTableLength(t, table); ++i) {
|
||||
if (ip <= lineNumberIp(lineNumberTableBody(t, table, i))) {
|
||||
return last;
|
||||
} else {
|
||||
last = lineNumberLine(lineNumberTableBody(t, table, i));
|
||||
}
|
||||
}
|
||||
return last;
|
||||
} else {
|
||||
return UnknownLine;
|
||||
}
|
||||
return ::lineNumber(static_cast<Thread*>(t), method, ip);
|
||||
}
|
||||
|
||||
virtual object*
|
||||
|
@ -3010,33 +3010,53 @@ printTrace(Thread* t, object exception)
|
||||
}
|
||||
|
||||
object
|
||||
makeTrace(Thread* t, uintptr_t start)
|
||||
makeTrace(Thread* t, Processor::StackWalker* walker)
|
||||
{
|
||||
Processor* p = t->m->processor;
|
||||
class Visitor: public Processor::StackVisitor {
|
||||
public:
|
||||
Visitor(Thread* t): t(t), trace(0), index(0), protector(t, &trace) { }
|
||||
|
||||
unsigned count = 0;
|
||||
for (uintptr_t frame = start;
|
||||
p->frameValid(t, frame);
|
||||
frame = p->frameNext(t, frame))
|
||||
{
|
||||
++ count;
|
||||
}
|
||||
virtual bool visit(Processor::StackWalker* walker) {
|
||||
if (trace == 0) {
|
||||
trace = makeArray(t, walker->count(), true);
|
||||
}
|
||||
|
||||
object trace = makeArray(t, count, true);
|
||||
PROTECT(t, trace);
|
||||
|
||||
unsigned index = 0;
|
||||
for (uintptr_t frame = start;
|
||||
p->frameValid(t, frame);
|
||||
frame = p->frameNext(t, frame))
|
||||
{
|
||||
object e = makeTraceElement
|
||||
(t, p->frameMethod(t, frame), p->frameIp(t, frame));
|
||||
set(t, trace, ArrayBody + (index * BytesPerWord), e);
|
||||
++ index;
|
||||
}
|
||||
object e = makeTraceElement(t, walker->method(), walker->ip());
|
||||
set(t, trace, ArrayBody + (index * BytesPerWord), e);
|
||||
++ index;
|
||||
return true;
|
||||
}
|
||||
|
||||
return trace;
|
||||
Thread* t;
|
||||
object trace;
|
||||
unsigned index;
|
||||
Thread::SingleProtector protector;
|
||||
} v(t);
|
||||
|
||||
walker->walk(&v);
|
||||
|
||||
return v.trace;
|
||||
}
|
||||
|
||||
object
|
||||
makeTrace(Thread* t)
|
||||
{
|
||||
class Visitor: public Processor::StackVisitor {
|
||||
public:
|
||||
Visitor(Thread* t): t(t), trace(0) { }
|
||||
|
||||
virtual bool visit(Processor::StackWalker* walker) {
|
||||
trace = makeTrace(t, walker);
|
||||
return false;
|
||||
}
|
||||
|
||||
Thread* t;
|
||||
object trace;
|
||||
} v(t);
|
||||
|
||||
t->m->processor->walkStack(t, &v);
|
||||
|
||||
return v.trace;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1505,13 +1505,10 @@ baseSize(Thread* t, object o, object class_)
|
||||
}
|
||||
|
||||
object
|
||||
makeTrace(Thread* t, uintptr_t start);
|
||||
makeTrace(Thread* t, Processor::StackWalker* walker);
|
||||
|
||||
inline object
|
||||
makeTrace(Thread* t)
|
||||
{
|
||||
return makeTrace(t, t->m->processor->frameStart(t));
|
||||
}
|
||||
object
|
||||
makeTrace(Thread* t);
|
||||
|
||||
inline object
|
||||
makeRuntimeException(Thread* t, object message)
|
||||
|
@ -9,6 +9,28 @@ namespace vm {
|
||||
|
||||
class Processor {
|
||||
public:
|
||||
class StackWalker;
|
||||
|
||||
class StackVisitor {
|
||||
public:
|
||||
virtual ~StackVisitor() { }
|
||||
|
||||
virtual bool visit(StackWalker* walker) = 0;
|
||||
};
|
||||
|
||||
class StackWalker {
|
||||
public:
|
||||
virtual ~StackWalker() { }
|
||||
|
||||
virtual void walk(StackVisitor* v) = 0;
|
||||
|
||||
virtual object method() = 0;
|
||||
|
||||
virtual int ip() = 0;
|
||||
|
||||
virtual unsigned count() = 0;
|
||||
};
|
||||
|
||||
virtual ~Processor() { }
|
||||
|
||||
virtual Thread*
|
||||
@ -51,23 +73,11 @@ class Processor {
|
||||
virtual void
|
||||
visitObjects(Thread* t, Heap::Visitor* v) = 0;
|
||||
|
||||
virtual uintptr_t
|
||||
frameStart(Thread* t) = 0;
|
||||
|
||||
virtual uintptr_t
|
||||
frameNext(Thread* t, uintptr_t frame) = 0;
|
||||
|
||||
virtual bool
|
||||
frameValid(Thread* t, uintptr_t frame) = 0;
|
||||
|
||||
virtual object
|
||||
frameMethod(Thread* t, uintptr_t frame) = 0;
|
||||
|
||||
virtual unsigned
|
||||
frameIp(Thread* t, uintptr_t frame) = 0;
|
||||
virtual void
|
||||
walkStack(Thread* t, StackVisitor* v) = 0;
|
||||
|
||||
virtual int
|
||||
lineNumber(Thread* t, object method, unsigned ip) = 0;
|
||||
lineNumber(Thread* t, object method, int ip) = 0;
|
||||
|
||||
virtual object*
|
||||
makeLocalReference(Thread* t, object o) = 0;
|
||||
|
@ -89,8 +89,20 @@
|
||||
|
||||
(type traceElement
|
||||
(object method)
|
||||
(int32_t ip))
|
||||
(int ip))
|
||||
|
||||
(type treeNode
|
||||
(intptr_t key))
|
||||
|
||||
(type traceNode
|
||||
(extends treeNode)
|
||||
(object method)
|
||||
(void* handler)
|
||||
(uint16_t line)
|
||||
(uint8_t virtualCall)
|
||||
(object target)
|
||||
(array uintptr_t map))
|
||||
|
||||
(type array
|
||||
(noassert array object body))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user