mirror of
https://github.com/corda/corda.git
synced 2025-01-19 03:06:36 +00:00
more progress on general stack tracing
This commit is contained in:
parent
ebffc5852c
commit
2d6eebf4d1
176
src/compile.cpp
176
src/compile.cpp
@ -1568,6 +1568,14 @@ checkCast(MyThread* t, object class_, object o)
|
||||
}
|
||||
}
|
||||
|
||||
void FORCE_ALIGN
|
||||
gcIfNecessary(MyThread* t)
|
||||
{
|
||||
if (UNLIKELY(t->backupHeap)) {
|
||||
collect(t, Heap::MinorCollection);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
pushReturnValue(MyThread* t, Frame* frame, unsigned code)
|
||||
{
|
||||
@ -1606,16 +1614,36 @@ pushReturnValue(MyThread* t, Frame* frame, unsigned code)
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
defaultCompiled(MyThread* t);
|
||||
|
||||
object
|
||||
nativeCompiled(MyThread* t);
|
||||
|
||||
void
|
||||
compileDirectInvoke(MyThread* t, Frame* frame, object target)
|
||||
{
|
||||
Compiler* c = frame->c;
|
||||
|
||||
c->alignedCall
|
||||
(c->constant
|
||||
(reinterpret_cast<intptr_t>
|
||||
(&singletonBody(t, methodCompiled(t, target), 0))),
|
||||
frame->trace(target, false));
|
||||
if (methodFlags(t, target) & ACC_NATIVE) {
|
||||
c->call
|
||||
(c->constant
|
||||
(reinterpret_cast<intptr_t>
|
||||
(&singletonBody(t, nativeCompiled(t), 0))),
|
||||
frame->trace(target, false));
|
||||
} else if (methodCompiled(t, target) == defaultCompiled(t)) {
|
||||
c->alignedCall
|
||||
(c->constant
|
||||
(reinterpret_cast<intptr_t>
|
||||
(&singletonBody(t, defaultCompiled(t), 0))),
|
||||
frame->trace(target, false));
|
||||
} else {
|
||||
c->call
|
||||
(c->constant
|
||||
(reinterpret_cast<intptr_t>
|
||||
(&singletonBody(t, methodCompiled(t, target), 0))),
|
||||
frame->trace(0, false));
|
||||
}
|
||||
|
||||
frame->pop(methodParameterFootprint(t, target));
|
||||
|
||||
@ -1673,7 +1701,8 @@ handleExit(MyThread* t, Frame* frame)
|
||||
}
|
||||
|
||||
void
|
||||
compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
||||
bool exceptionHandler = false)
|
||||
{
|
||||
uintptr_t stackMap[stackMapSizeInWords(t, initialFrame->context->method)];
|
||||
Frame myFrame(initialFrame, stackMap);
|
||||
@ -1694,6 +1723,15 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
|
||||
frame->startLogicalIp(ip);
|
||||
|
||||
if (exceptionHandler) {
|
||||
exceptionHandler = false;
|
||||
|
||||
c->indirectCall
|
||||
(c->constant(reinterpret_cast<intptr_t>(gcIfNecessary)),
|
||||
frame->trace(0, false),
|
||||
1, c->thread());
|
||||
}
|
||||
|
||||
// fprintf(stderr, "ip: %d map: %ld\n", ip, *(frame->map));
|
||||
|
||||
unsigned instruction = codeBody(t, code, ip++);
|
||||
@ -1717,8 +1755,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
c->cmp4(c->constant(0), index);
|
||||
c->jl(throw_);
|
||||
|
||||
c->cmp4(c->memory(array, ArrayLength, 0, 1, frame->trace(0, false)),
|
||||
index);
|
||||
c->cmp4(c->memory(array, ArrayLength, 0, 1), index);
|
||||
c->jl(load);
|
||||
|
||||
c->mark(throw_);
|
||||
@ -1791,8 +1828,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
c->cmp4(c->constant(0), index);
|
||||
c->jl(throw_);
|
||||
|
||||
c->cmp4(c->memory(array, ArrayLength, 0, 1, frame->trace(0, false)),
|
||||
index);
|
||||
c->cmp4(c->memory(array, ArrayLength, 0, 1), index);
|
||||
c->jl(store);
|
||||
|
||||
c->mark(throw_);
|
||||
@ -1906,8 +1942,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
|
||||
case arraylength: {
|
||||
Operand* array = frame->popObject();
|
||||
frame->pushInt4
|
||||
(c->memory(array, ArrayLength, 0, 1, frame->trace(0, false)));
|
||||
frame->pushInt4(c->memory(array, ArrayLength, 0, 1));
|
||||
c->release(array);
|
||||
} break;
|
||||
|
||||
@ -2322,43 +2357,32 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
table = frame->popObject();
|
||||
}
|
||||
|
||||
TraceElement* trace = 0;
|
||||
if (instruction == getfield) {
|
||||
trace = frame->trace(0, false);
|
||||
}
|
||||
|
||||
switch (fieldCode(t, field)) {
|
||||
case ByteField:
|
||||
case BooleanField:
|
||||
frame->pushInt1
|
||||
(c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
||||
frame->pushInt1(c->memory(table, fieldOffset(t, field), 0, 1));
|
||||
break;
|
||||
|
||||
case CharField:
|
||||
frame->pushInt2z
|
||||
(c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
||||
frame->pushInt2z(c->memory(table, fieldOffset(t, field), 0, 1));
|
||||
break;
|
||||
|
||||
case ShortField:
|
||||
frame->pushInt2
|
||||
(c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
||||
frame->pushInt2(c->memory(table, fieldOffset(t, field), 0, 1));
|
||||
break;
|
||||
|
||||
case FloatField:
|
||||
case IntField:
|
||||
frame->pushInt4
|
||||
(c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
||||
frame->pushInt4(c->memory(table, fieldOffset(t, field), 0, 1));
|
||||
break;
|
||||
|
||||
case DoubleField:
|
||||
case LongField:
|
||||
frame->pushLong
|
||||
(c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
||||
frame->pushLong(c->memory(table, fieldOffset(t, field), 0, 1));
|
||||
break;
|
||||
|
||||
case ObjectField:
|
||||
frame->pushObject
|
||||
(c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
||||
frame->pushObject(c->memory(table, fieldOffset(t, field), 0, 1));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -2723,7 +2747,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
Operand* instance = c->stack(frame->stack, parameterFootprint - 1);
|
||||
Operand* class_ = c->temporary();
|
||||
|
||||
mov(c, c->memory(instance, 0, 0, 1, frame->trace(0, false)), class_);
|
||||
mov(c, c->memory(instance, 0, 0, 1), class_);
|
||||
and_(c, c->constant(PointerMask), class_);
|
||||
|
||||
c->call(c->memory(class_, offset, 0, 1), frame->trace(target, true));
|
||||
@ -3313,30 +3337,25 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
||||
table = frame->popObject();
|
||||
}
|
||||
|
||||
TraceElement* trace = 0;
|
||||
if (instruction == putfield and fieldCode(t, field) != ObjectField) {
|
||||
trace = frame->trace(0, false);
|
||||
}
|
||||
|
||||
switch (fieldCode(t, field)) {
|
||||
case ByteField:
|
||||
case BooleanField:
|
||||
c->mov1(value, c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
||||
c->mov1(value, c->memory(table, fieldOffset(t, field), 0, 1));
|
||||
break;
|
||||
|
||||
case CharField:
|
||||
case ShortField:
|
||||
c->mov2(value, c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
||||
c->mov2(value, c->memory(table, fieldOffset(t, field), 0, 1));
|
||||
break;
|
||||
|
||||
case FloatField:
|
||||
case IntField:
|
||||
c->mov4(value, c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
||||
c->mov4(value, c->memory(table, fieldOffset(t, field), 0, 1));
|
||||
break;
|
||||
|
||||
case DoubleField:
|
||||
case LongField:
|
||||
c->mov8(value, c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
||||
c->mov8(value, c->memory(table, fieldOffset(t, field), 0, 1));
|
||||
break;
|
||||
|
||||
case ObjectField:
|
||||
@ -3931,7 +3950,7 @@ compile(MyThread* t, Context* context)
|
||||
frame2.clear(localSize(t, context->method) + i);
|
||||
}
|
||||
|
||||
compile(t, &frame2, exceptionHandlerIp(eh));
|
||||
compile(t, &frame2, exceptionHandlerIp(eh), true);
|
||||
if (UNLIKELY(t->exception)) return 0;
|
||||
|
||||
eventIndex = calculateFrameMaps(t, context, 0, eventIndex);
|
||||
@ -4519,6 +4538,28 @@ invoke(Thread* thread, object method, ArgumentList* arguments)
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned
|
||||
traceSize(Thread* t)
|
||||
{
|
||||
class Counter: public Processor::StackVisitor {
|
||||
public:
|
||||
Counter(Thread* t): t(t), count(0) { }
|
||||
|
||||
virtual bool visit(Processor::StackWalker*) {
|
||||
++ count;
|
||||
return true;
|
||||
}
|
||||
|
||||
Thread* t;
|
||||
unsigned count;
|
||||
} counter(t);
|
||||
|
||||
t->m->processor->walkStack(t, &counter);
|
||||
|
||||
return FixedSizeOfArray + (counter.count * ArrayElementSizeOfArray)
|
||||
+ (counter.count * FixedSizeOfTraceElement);
|
||||
}
|
||||
|
||||
class SegFaultHandler: public System::SignalHandler {
|
||||
public:
|
||||
SegFaultHandler(): m(0) { }
|
||||
@ -4533,6 +4574,9 @@ class SegFaultHandler: public System::SignalHandler {
|
||||
t->ip = *ip;
|
||||
t->base = *base;
|
||||
t->stack = *stack;
|
||||
|
||||
ensure(t, FixedSizeOfNullPointerException + traceSize(t));
|
||||
|
||||
t->exception = makeNullPointerException(t);
|
||||
|
||||
findUnwindTarget(t, ip, base, stack);
|
||||
@ -4830,6 +4874,46 @@ class MyProcessor: public Processor {
|
||||
|
||||
allocator->free(this, sizeof(*this), false);
|
||||
}
|
||||
|
||||
virtual object getStackTrace(Thread* vmt, Thread* vmTarget) {
|
||||
MyThread* t = static_cast<MyThread*>(vmt);
|
||||
MyThread* target = static_cast<MyThread*>(vmTarget);
|
||||
|
||||
class Visitor: public System::ThreadVisitor {
|
||||
public:
|
||||
Visitor(MyThread* t, MyThread* target): t(t), target(target) { }
|
||||
|
||||
virtual void visit(void* ip, void* base, void* stack) {
|
||||
ensure(t, traceSize(t));
|
||||
|
||||
void* oldIp = target->ip;
|
||||
void* oldBase = target->ip;
|
||||
void* oldStack = target->stack;
|
||||
|
||||
target->ip = ip;
|
||||
target->base = base;
|
||||
target->stack = stack;
|
||||
|
||||
trace = makeTrace(t, target);
|
||||
|
||||
target->ip = oldIp;
|
||||
target->base = oldBase;
|
||||
target->stack = oldStack;
|
||||
}
|
||||
|
||||
MyThread* t;
|
||||
MyThread* target;
|
||||
object trace;
|
||||
} visitor(t, target);
|
||||
|
||||
if (t->backupHeap) {
|
||||
PROTECT(t, visitor.trace);
|
||||
|
||||
collect(t, Heap::MinorCollection);
|
||||
}
|
||||
|
||||
return visitor.trace;
|
||||
}
|
||||
|
||||
System* s;
|
||||
Allocator* allocator;
|
||||
@ -4884,6 +4968,18 @@ processor(MyThread* t)
|
||||
return p;
|
||||
}
|
||||
|
||||
object
|
||||
defaultCompiled(MyThread* t)
|
||||
{
|
||||
return processor(t)->getDefaultCompiled(t);
|
||||
}
|
||||
|
||||
object
|
||||
nativeCompiled(MyThread* t)
|
||||
{
|
||||
return processor(t)->getNativeCompiled(t);
|
||||
}
|
||||
|
||||
void
|
||||
compile(MyThread* t, object method)
|
||||
{
|
||||
|
@ -326,7 +326,7 @@ register_(Context* c, Register = NoRegister, Register = NoRegister);
|
||||
|
||||
MemoryOperand*
|
||||
memory(Context* c, MyOperand* base, int displacement,
|
||||
MyOperand* index, unsigned scale, Compiler::TraceHandler* traceHandler);
|
||||
MyOperand* index, unsigned scale);
|
||||
|
||||
class MyOperand: public Operand {
|
||||
public:
|
||||
@ -630,17 +630,15 @@ class AbsoluteOperand: public MyOperand {
|
||||
class MemoryOperand: public MyOperand {
|
||||
public:
|
||||
MemoryOperand(MyOperand* base, int displacement, MyOperand* index,
|
||||
unsigned scale, Compiler::TraceHandler* traceHandler):
|
||||
unsigned scale):
|
||||
base(base),
|
||||
displacement(displacement),
|
||||
index(index),
|
||||
scale(scale),
|
||||
traceHandler(traceHandler)
|
||||
scale(scale)
|
||||
{ }
|
||||
|
||||
MemoryOperand* high(Context* c) {
|
||||
return memory
|
||||
(c, base, displacement + BytesPerWord, index, scale, traceHandler);
|
||||
return memory(c, base, displacement + BytesPerWord, index, scale);
|
||||
}
|
||||
|
||||
virtual Register asRegister(Context*);
|
||||
@ -670,7 +668,6 @@ class MemoryOperand: public MyOperand {
|
||||
int displacement;
|
||||
MyOperand* index;
|
||||
unsigned scale;
|
||||
Compiler::TraceHandler* traceHandler;
|
||||
};
|
||||
|
||||
class CodePromiseTask: public Task {
|
||||
@ -722,10 +719,10 @@ register_(Context* c, Register v, Register h)
|
||||
|
||||
MemoryOperand*
|
||||
memory(Context* c, MyOperand* base, int displacement,
|
||||
MyOperand* index, unsigned scale, Compiler::TraceHandler* traceHandler)
|
||||
MyOperand* index, unsigned scale)
|
||||
{
|
||||
return new (c->zone->allocate(sizeof(MemoryOperand)))
|
||||
MemoryOperand(base, displacement, index, scale, traceHandler);
|
||||
MemoryOperand(base, displacement, index, scale);
|
||||
}
|
||||
|
||||
RegisterOperand*
|
||||
@ -1038,8 +1035,7 @@ pushed(Context* c, MyStack* stack)
|
||||
int index = (stack ? stack->index + 1 : 0);
|
||||
|
||||
MyOperand* value = memory
|
||||
(c, register_(c, rbp), - (c->reserved + index + 1) * BytesPerWord, 0, 1,
|
||||
0);
|
||||
(c, register_(c, rbp), - (c->reserved + index + 1) * BytesPerWord, 0, 1);
|
||||
|
||||
stack = new (c->zone->allocate(sizeof(MyStack)))
|
||||
MyStack(value, index, stack);
|
||||
@ -1183,12 +1179,6 @@ encode(Context* c, uint8_t instruction, int a, MemoryOperand* b, bool rex)
|
||||
Register r = b->base->asRegister(c);
|
||||
int index = b->index ? b->index->asRegister(c) : -1;
|
||||
|
||||
if (b->traceHandler and c->codeLength >= 0) {
|
||||
b->traceHandler->handleTrace
|
||||
(resolved(c, reinterpret_cast<intptr_t>
|
||||
(c->code.data + c->code.length())));
|
||||
}
|
||||
|
||||
if (rex) {
|
||||
::rex(c);
|
||||
}
|
||||
@ -1201,12 +1191,6 @@ encode2(Context* c, uint16_t instruction, int a, MemoryOperand* b, bool rex)
|
||||
Register r = b->base->asRegister(c);
|
||||
int index = b->index ? b->index->asRegister(c) : -1;
|
||||
|
||||
if (b->traceHandler and c->codeLength >= 0) {
|
||||
b->traceHandler->handleTrace
|
||||
(resolved(c, reinterpret_cast<intptr_t>
|
||||
(c->code.data + c->code.length())));
|
||||
}
|
||||
|
||||
if (rex) {
|
||||
::rex(c);
|
||||
}
|
||||
@ -1572,7 +1556,7 @@ RegisterOperand::accept(Context* c, Operation op,
|
||||
|
||||
RegisterOperand* tmp = temporary(c);
|
||||
tmp->accept(c, mov, ::value(c, operand));
|
||||
accept(c, cmp, memory(c, tmp, 0, 0, 1, 0));
|
||||
accept(c, cmp, memory(c, tmp, 0, 0, 1));
|
||||
tmp->release(c);
|
||||
} break;
|
||||
|
||||
@ -1581,7 +1565,7 @@ RegisterOperand::accept(Context* c, Operation op,
|
||||
assert(c, BytesPerWord == 8 or op == mov4); // todo
|
||||
|
||||
accept(c, mov, ::value(c, operand));
|
||||
accept(c, mov, memory(c, this, 0, 0, 1, 0));
|
||||
accept(c, mov, memory(c, this, 0, 0, 1));
|
||||
} break;
|
||||
|
||||
default: abort(c);
|
||||
@ -1759,7 +1743,7 @@ absoluteApply(Context* c, MyOperand::Operation op,
|
||||
{
|
||||
RegisterOperand* tmp = temporary(c);
|
||||
tmp->accept(c, MyOperand::mov, value(c, operand));
|
||||
memory(c, tmp, 0, 0, 1, 0)->apply(c, op);
|
||||
memory(c, tmp, 0, 0, 1)->apply(c, op);
|
||||
tmp->release(c);
|
||||
}
|
||||
|
||||
@ -2797,11 +2781,10 @@ class MyCompiler: public Compiler {
|
||||
}
|
||||
|
||||
virtual Operand* memory(Operand* base, int displacement,
|
||||
Operand* index, unsigned scale,
|
||||
TraceHandler* trace)
|
||||
Operand* index, unsigned scale)
|
||||
{
|
||||
return ::memory(&c, static_cast<MyOperand*>(base), displacement,
|
||||
static_cast<MyOperand*>(index), scale, trace);
|
||||
static_cast<MyOperand*>(index), scale);
|
||||
}
|
||||
|
||||
virtual void prologue() {
|
||||
|
@ -51,8 +51,7 @@ class Compiler {
|
||||
virtual Operand* memory(Operand* base,
|
||||
int displacement = 0,
|
||||
Operand* index = 0,
|
||||
unsigned scale = 1,
|
||||
TraceHandler* traceHandler = 0) = 0;
|
||||
unsigned scale = 1) = 0;
|
||||
|
||||
virtual Operand* stack() = 0;
|
||||
virtual Operand* base() = 0;
|
||||
|
@ -501,6 +501,13 @@ postCollect(Thread* t)
|
||||
t->heapOffset = 0;
|
||||
t->heapIndex = 0;
|
||||
|
||||
if (t->backupHeap) {
|
||||
t->m->heap->free
|
||||
(t->backupHeap, t->backupHeapSizeInWords * BytesPerWord, false);
|
||||
t->backupHeapIndex = 0;
|
||||
t->backupHeapSizeInWords = 0;
|
||||
}
|
||||
|
||||
for (Thread* c = t->child; c; c = c->peer) {
|
||||
postCollect(c);
|
||||
}
|
||||
@ -1740,7 +1747,10 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
||||
runnable(this),
|
||||
defaultHeap(static_cast<uintptr_t*>
|
||||
(m->heap->allocate(HeapSizeInBytes, false))),
|
||||
heap(defaultHeap)
|
||||
heap(defaultHeap),
|
||||
backupHeap(0),
|
||||
backupHeapIndex(0),
|
||||
backupHeapSizeInWords(0)
|
||||
#ifdef VM_STRESS
|
||||
, stress(false)
|
||||
#endif // VM_STRESS
|
||||
@ -2043,6 +2053,16 @@ object
|
||||
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
||||
unsigned sizeInBytes, bool executable, bool objectMask)
|
||||
{
|
||||
if (t->backupHeap) {
|
||||
expect(t, t->backupHeapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||
<= t->backupHeapSizeInWords);
|
||||
|
||||
object o = reinterpret_cast<object>(t->backupHeap + t->backupHeapIndex);
|
||||
t->backupHeapIndex += ceiling(sizeInBytes, BytesPerWord);
|
||||
cast<object>(o, 0) = 0;
|
||||
return o;
|
||||
}
|
||||
|
||||
ACQUIRE_RAW(t, t->m->stateLock);
|
||||
|
||||
while (t->m->exclusive and t->m->exclusive != t) {
|
||||
@ -2058,7 +2078,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
||||
t->heap = 0;
|
||||
}
|
||||
} else if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||
>= Thread::HeapSizeInWords)
|
||||
> Thread::HeapSizeInWords)
|
||||
{
|
||||
t->heap = 0;
|
||||
if (t->m->heapPoolIndex < Machine::HeapPoolSize) {
|
||||
@ -2839,7 +2859,7 @@ makeTrace(Thread* t, Processor::StackWalker* walker)
|
||||
}
|
||||
|
||||
object
|
||||
makeTrace(Thread* t)
|
||||
makeTrace(Thread* t, Thread* target)
|
||||
{
|
||||
class Visitor: public Processor::StackVisitor {
|
||||
public:
|
||||
@ -2854,7 +2874,7 @@ makeTrace(Thread* t)
|
||||
object trace;
|
||||
} v(t);
|
||||
|
||||
t->m->processor->walkStack(t, &v);
|
||||
t->m->processor->walkStack(target, &v);
|
||||
|
||||
return v.trace ? v.trace : makeArray(t, 0, true);
|
||||
}
|
||||
|
@ -1288,6 +1288,9 @@ class Thread {
|
||||
Runnable runnable;
|
||||
uintptr_t* defaultHeap;
|
||||
uintptr_t* heap;
|
||||
uintptr_t* backupHeap;
|
||||
unsigned backupHeapIndex;
|
||||
unsigned backupHeapSizeInWords;
|
||||
#ifdef VM_STRESS
|
||||
bool stress;
|
||||
#endif // VM_STRESS
|
||||
@ -1426,6 +1429,20 @@ expect(Thread* t, bool v)
|
||||
expect(t->m->system, v);
|
||||
}
|
||||
|
||||
inline void
|
||||
ensure(Thread* t, unsigned sizeInBytes)
|
||||
{
|
||||
if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||
> Thread::HeapSizeInWords)
|
||||
{
|
||||
expect(t, t->backupHeap == 0);
|
||||
t->backupHeap = static_cast<uintptr_t*>
|
||||
(t->m->heap->allocate(pad(sizeInBytes), false));
|
||||
t->backupHeapIndex = 0;
|
||||
t->backupHeapSizeInWords = ceiling(sizeInBytes, BytesPerWord);
|
||||
}
|
||||
}
|
||||
|
||||
object
|
||||
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask);
|
||||
|
||||
@ -1448,7 +1465,7 @@ allocate(Thread* t, unsigned sizeInBytes, bool objectMask)
|
||||
stress(t);
|
||||
|
||||
if (UNLIKELY(t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||
>= Thread::HeapSizeInWords
|
||||
> Thread::HeapSizeInWords
|
||||
or t->m->exclusive))
|
||||
{
|
||||
return allocate2(t, sizeInBytes, objectMask);
|
||||
@ -1527,7 +1544,13 @@ object
|
||||
makeTrace(Thread* t, Processor::StackWalker* walker);
|
||||
|
||||
object
|
||||
makeTrace(Thread* t);
|
||||
makeTrace(Thread* t, Thread* target);
|
||||
|
||||
inline object
|
||||
makeTrace(Thread* t)
|
||||
{
|
||||
return makeTrace(t, t);
|
||||
}
|
||||
|
||||
inline object
|
||||
makeRuntimeException(Thread* t, object message)
|
||||
|
204
src/posix.cpp
204
src/posix.cpp
@ -35,9 +35,6 @@ using namespace vm;
|
||||
|
||||
namespace {
|
||||
|
||||
System::SignalHandler* segFaultHandler = 0;
|
||||
struct sigaction oldSegFaultHandler;
|
||||
|
||||
class MutexResource {
|
||||
public:
|
||||
MutexResource(pthread_mutex_t& m): m(&m) {
|
||||
@ -52,12 +49,22 @@ class MutexResource {
|
||||
pthread_mutex_t* m;
|
||||
};
|
||||
|
||||
const int InterruptSignal = SIGUSR2;
|
||||
const int VisitSignal = SIGUSR1;
|
||||
#ifdef __APPLE__
|
||||
const int SegFaultSignal = SIGBUS;
|
||||
#else
|
||||
const int SegFaultSignal = SIGSEGV;
|
||||
#endif
|
||||
const int InterruptSignal = SIGUSR2;
|
||||
|
||||
const unsigned VisitSignalIndex = 0;
|
||||
const unsigned SegFaultSignalIndex = 1;
|
||||
const unsigned InterruptSignalIndex = 2;
|
||||
|
||||
class MySystem;
|
||||
MySystem* system;
|
||||
|
||||
const int signals[] = { VisitSignal, SegFaultSignal, InterruptSignal };
|
||||
|
||||
#ifdef __x86_64__
|
||||
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP])
|
||||
@ -86,41 +93,7 @@ const int SegFaultSignal = SIGSEGV;
|
||||
#endif
|
||||
|
||||
void
|
||||
handleSignal(int signal, siginfo_t* info, void* context)
|
||||
{
|
||||
if (signal == SegFaultSignal) {
|
||||
ucontext_t* c = static_cast<ucontext_t*>(context);
|
||||
|
||||
void* ip = reinterpret_cast<void*>(IP_REGISTER(c));
|
||||
void* base = reinterpret_cast<void*>(BASE_REGISTER(c));
|
||||
void* stack = reinterpret_cast<void*>(STACK_REGISTER(c));
|
||||
void* thread = reinterpret_cast<void*>(THREAD_REGISTER(c));
|
||||
|
||||
bool jump = segFaultHandler->handleSignal
|
||||
(&ip, &base, &stack, &thread);
|
||||
|
||||
if (jump) {
|
||||
// I'd like to use setcontext here (and get rid of the
|
||||
// sigprocmask call), but it doesn't work on my Linux x86_64
|
||||
// system, and I can't tell from the documentation if it's even
|
||||
// supposed to work.
|
||||
|
||||
sigset_t set;
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SegFaultSignal);
|
||||
sigprocmask(SIG_UNBLOCK, &set, 0);
|
||||
|
||||
vmJump(ip, base, stack, thread);
|
||||
} else if (oldSegFaultHandler.sa_flags & SA_SIGINFO) {
|
||||
oldSegFaultHandler.sa_sigaction(signal, info, context);
|
||||
} else if (oldSegFaultHandler.sa_handler) {
|
||||
oldSegFaultHandler.sa_handler(signal);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
handleSignal(int signal, siginfo_t* info, void* context);
|
||||
|
||||
void*
|
||||
run(void* r)
|
||||
@ -547,15 +520,33 @@ class MySystem: public System {
|
||||
System::Library* next_;
|
||||
};
|
||||
|
||||
MySystem() {
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(struct sigaction));
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = handleSignal;
|
||||
MySystem(): threadVisitor(0), visitTarget(0) {
|
||||
expect(this, system == 0);
|
||||
system = this;
|
||||
|
||||
registerHandler(&nullHandler, InterruptSignalIndex);
|
||||
registerHandler(&nullHandler, VisitSignalIndex);
|
||||
|
||||
expect(this, make(&visitLock) == 0);
|
||||
}
|
||||
|
||||
int registerHandler(System::SignalHandler* handler, int index) {
|
||||
if (handler) {
|
||||
handlers[index] = handler;
|
||||
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(struct sigaction));
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = handleSignal;
|
||||
|
||||
int rv UNUSED = sigaction(InterruptSignal, &sa, 0);
|
||||
expect(this, rv == 0);
|
||||
return sigaction(signals[index], &sa, oldHandlers + index);
|
||||
} else if (handlers[index]) {
|
||||
handlers[index] = 0;
|
||||
return sigaction(signals[index], oldHandlers + index, 0);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void* tryAllocate(unsigned size, bool executable) {
|
||||
@ -625,22 +616,32 @@ class MySystem: public System {
|
||||
}
|
||||
|
||||
virtual Status handleSegFault(SignalHandler* handler) {
|
||||
if (handler) {
|
||||
segFaultHandler = handler;
|
||||
return registerHandler(handler, SegFaultSignalIndex);
|
||||
}
|
||||
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(struct sigaction));
|
||||
sigemptyset(&(sa.sa_mask));
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = handleSignal;
|
||||
|
||||
return sigaction(SegFaultSignal, &sa, &oldSegFaultHandler);
|
||||
} else if (segFaultHandler) {
|
||||
segFaultHandler = 0;
|
||||
return sigaction(SegFaultSignal, &oldSegFaultHandler, 0);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
virtual Status visit(System::Thread* st, System::Thread* sTarget,
|
||||
ThreadVisitor* visitor)
|
||||
{
|
||||
assert(this, st != sTarget);
|
||||
|
||||
Thread* t = static_cast<Thread*>(st);
|
||||
Thread* target = static_cast<Thread*>(sTarget);
|
||||
|
||||
ACQUIRE_MONITOR(t, visitLock);
|
||||
|
||||
while (threadVisitor) visitLock->wait(t, 0);
|
||||
|
||||
threadVisitor = visitor;
|
||||
visitTarget = target;
|
||||
|
||||
int rv = pthread_kill(target->thread, VisitSignal);
|
||||
expect(this, rv == 0);
|
||||
|
||||
while (visitTarget) visitLock->wait(t, 0);
|
||||
|
||||
threadVisitor = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
||||
@ -754,10 +755,89 @@ class MySystem: public System {
|
||||
}
|
||||
|
||||
virtual void dispose() {
|
||||
visitLock->dispose();
|
||||
|
||||
registerHandler(0, InterruptSignalIndex);
|
||||
registerHandler(0, VisitSignalIndex);
|
||||
system = 0;
|
||||
|
||||
::free(this);
|
||||
}
|
||||
|
||||
|
||||
class NullSignalHandler: public SignalHandler {
|
||||
virtual bool handleSignal(void**, void**, void**, void**) { return false; }
|
||||
} nullHandler;
|
||||
|
||||
SignalHandler* handlers[3];
|
||||
struct sigaction oldHandlers[3];
|
||||
|
||||
ThreadVisitor* threadVisitor;
|
||||
Thread* visitTarget;
|
||||
System::Monitor* visitLock;
|
||||
};
|
||||
|
||||
void
|
||||
handleSignal(int signal, siginfo_t* info, void* context)
|
||||
{
|
||||
ucontext_t* c = static_cast<ucontext_t*>(context);
|
||||
|
||||
void* ip = reinterpret_cast<void*>(IP_REGISTER(c));
|
||||
void* base = reinterpret_cast<void*>(BASE_REGISTER(c));
|
||||
void* stack = reinterpret_cast<void*>(STACK_REGISTER(c));
|
||||
void* thread = reinterpret_cast<void*>(THREAD_REGISTER(c));
|
||||
|
||||
unsigned index;
|
||||
|
||||
switch (signal) {
|
||||
case VisitSignal: {
|
||||
index = VisitSignalIndex;
|
||||
|
||||
system->threadVisitor->visit(ip, base, stack);
|
||||
|
||||
System::Thread* t = system->visitTarget;
|
||||
system->visitTarget = 0;
|
||||
system->visitLock->notifyAll(t);
|
||||
} break;
|
||||
|
||||
case SegFaultSignal: {
|
||||
index = SegFaultSignalIndex;
|
||||
|
||||
bool jump = system->handlers[index]->handleSignal
|
||||
(&ip, &base, &stack, &thread);
|
||||
|
||||
if (jump) {
|
||||
// I'd like to use setcontext here (and get rid of the
|
||||
// sigprocmask call), but it doesn't work on my Linux x86_64
|
||||
// system, and I can't tell from the documentation if it's even
|
||||
// supposed to work.
|
||||
|
||||
sigset_t set;
|
||||
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SegFaultSignal);
|
||||
sigprocmask(SIG_UNBLOCK, &set, 0);
|
||||
|
||||
vmJump(ip, base, stack, thread);
|
||||
}
|
||||
} break;
|
||||
|
||||
case InterruptSignal: {
|
||||
index = InterruptSignalIndex;
|
||||
} break;
|
||||
|
||||
default: abort();
|
||||
}
|
||||
|
||||
if (system->oldHandlers[index].sa_flags & SA_SIGINFO) {
|
||||
system->oldHandlers[index].sa_sigaction(signal, info, context);
|
||||
} else if (system->oldHandlers[index].sa_handler) {
|
||||
system->oldHandlers[index].sa_handler(signal);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace vm {
|
||||
|
26
src/system.h
26
src/system.h
@ -34,6 +34,12 @@ class System {
|
||||
virtual void dispose() = 0;
|
||||
};
|
||||
|
||||
class ThreadVisitor {
|
||||
public:
|
||||
virtual ~ThreadVisitor() { }
|
||||
virtual void visit(void* ip, void* base, void* stack) = 0;
|
||||
};
|
||||
|
||||
class Runnable {
|
||||
public:
|
||||
virtual ~Runnable() { }
|
||||
@ -99,6 +105,21 @@ class System {
|
||||
void** thread) = 0;
|
||||
};
|
||||
|
||||
class MonitorResource {
|
||||
public:
|
||||
MonitorResource(System::Thread* t, System::Monitor* m): t(t), m(m) {
|
||||
m->acquire(t);
|
||||
}
|
||||
|
||||
~MonitorResource() {
|
||||
m->release(t);
|
||||
}
|
||||
|
||||
private:
|
||||
System::Thread* t;
|
||||
System::Monitor* m;
|
||||
};
|
||||
|
||||
virtual ~System() { }
|
||||
|
||||
virtual bool success(Status) = 0;
|
||||
@ -110,6 +131,8 @@ class System {
|
||||
virtual Status make(Monitor**) = 0;
|
||||
virtual Status make(Local**) = 0;
|
||||
virtual Status handleSegFault(SignalHandler* handler) = 0;
|
||||
virtual Status visit(Thread* thread, Thread* target,
|
||||
ThreadVisitor* visitor) = 0;
|
||||
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
||||
unsigned count, unsigned size,
|
||||
unsigned returnType) = 0;
|
||||
@ -123,6 +146,9 @@ class System {
|
||||
virtual void dispose() = 0;
|
||||
};
|
||||
|
||||
#define ACQUIRE_MONITOR(t, m) \
|
||||
System::MonitorResource MAKE_NAME(monitorResource_) (t, m)
|
||||
|
||||
inline void NO_RETURN
|
||||
abort(System* s)
|
||||
{
|
||||
|
@ -1507,7 +1507,7 @@ writeOffset(Output* out, Object* offset, bool allocationStyle = false)
|
||||
out->write("length");
|
||||
} else {
|
||||
out->write(typeName(memberOwner(o)));
|
||||
out->write(capitalize("length"));
|
||||
out->write("Length");
|
||||
out->write("(o)");
|
||||
}
|
||||
out->write(" * ");
|
||||
@ -1762,6 +1762,49 @@ typeFixedSize(Object* type)
|
||||
return length;
|
||||
}
|
||||
|
||||
unsigned
|
||||
typeArrayElementSize(Object* type)
|
||||
{
|
||||
for (MemberIterator it(type); it.hasMore();) {
|
||||
Object* m = it.next();
|
||||
switch (m->type) {
|
||||
case Object::Scalar: break;
|
||||
|
||||
case Object::Array: {
|
||||
return memberElementSize(m);
|
||||
} break;
|
||||
|
||||
default: UNREACHABLE;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
writeSizes(Output* out, Object* declarations)
|
||||
{
|
||||
for (Object* p = declarations; p; p = cdr(p)) {
|
||||
Object* o = car(p);
|
||||
switch (o->type) {
|
||||
case Object::Type: {
|
||||
out->write("const unsigned FixedSizeOf");
|
||||
out->write(capitalize(typeName(o)));
|
||||
out->write(" = ");
|
||||
out->write(typeFixedSize(o));
|
||||
out->write(";\n\n");
|
||||
|
||||
out->write("const unsigned ArrayElementSizeOf");
|
||||
out->write(capitalize(typeName(o)));
|
||||
out->write(" = ");
|
||||
out->write(typeArrayElementSize(o));
|
||||
out->write(";\n\n");
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char*
|
||||
obfuscate(const char* s)
|
||||
{
|
||||
@ -2049,24 +2092,6 @@ set(uint32_t* mask, unsigned index)
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
typeArrayElementSize(Object* type)
|
||||
{
|
||||
for (MemberIterator it(type); it.hasMore();) {
|
||||
Object* m = it.next();
|
||||
switch (m->type) {
|
||||
case Object::Scalar: break;
|
||||
|
||||
case Object::Array: {
|
||||
return memberElementSize(m);
|
||||
} break;
|
||||
|
||||
default: UNREACHABLE;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
typeObjectMask(Object* type)
|
||||
{
|
||||
@ -2274,6 +2299,7 @@ main(int ac, char** av)
|
||||
|
||||
writePods(&out, declarations);
|
||||
writeAccessors(&out, declarations);
|
||||
writeSizes(&out, declarations);
|
||||
writeInitializerDeclarations(&out, declarations);
|
||||
writeConstructorDeclarations(&out, declarations);
|
||||
}
|
||||
|
@ -23,6 +23,23 @@ using namespace vm;
|
||||
|
||||
namespace {
|
||||
|
||||
class MutexResource {
|
||||
public:
|
||||
MutexResource(System* s, HANDLE m): s(s), m(m) {
|
||||
int r UNUSED = WaitForSingleObject(m, INFINITE);
|
||||
assert(s, r == WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
~MutexResource() {
|
||||
bool success UNUSED = ReleaseMutex(m);
|
||||
assert(s, success);
|
||||
}
|
||||
|
||||
private:
|
||||
System* s;
|
||||
HANDLE m;
|
||||
};
|
||||
|
||||
System::SignalHandler* segFaultHandler = 0;
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER oldSegFaultHandler = 0;
|
||||
|
||||
@ -43,23 +60,6 @@ handleException(LPEXCEPTION_POINTERS e)
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
class MutexResource {
|
||||
public:
|
||||
MutexResource(System* s, HANDLE m): s(s), m(m) {
|
||||
int r UNUSED = WaitForSingleObject(m, INFINITE);
|
||||
assert(s, r == WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
~MutexResource() {
|
||||
bool success UNUSED = ReleaseMutex(m);
|
||||
assert(s, success);
|
||||
}
|
||||
|
||||
private:
|
||||
System* s;
|
||||
HANDLE m;
|
||||
};
|
||||
|
||||
DWORD WINAPI
|
||||
run(void* r)
|
||||
{
|
||||
@ -564,6 +564,39 @@ class MySystem: public System {
|
||||
}
|
||||
}
|
||||
|
||||
virtual Status visit(System::Thread* st, System::Thread* sTarget,
|
||||
ThreadVisitor* visitor)
|
||||
{
|
||||
assert(this, st != sTarget);
|
||||
|
||||
Thread* t = static_cast<Thread*>(st);
|
||||
Thread* target = static_cast<Thread*>(sTarget);
|
||||
|
||||
ACQUIRE_MONITOR(t, visitLock);
|
||||
|
||||
while (target->visitor) traceLock->wait(t);
|
||||
|
||||
target->visitor = visitor;
|
||||
|
||||
DWORD rv = SuspendThread(target->thread);
|
||||
expect(this, rv != -1);
|
||||
|
||||
CONTEXT context;
|
||||
rv = GetThreadContext(target->thread, &context);
|
||||
expect(this, rv);
|
||||
|
||||
visitor->visit(reinterpret_cast<void*>(context->Eip),
|
||||
reinterpret_cast<void*>(context->Ebp),
|
||||
reinterpret_cast<void*>(context->Esp));
|
||||
|
||||
rv = ResumeThread(target->thread);
|
||||
expect(this, rv != -1);
|
||||
|
||||
target->visitor = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
||||
unsigned count, unsigned size, unsigned returnType)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user