more progress on general stack tracing

This commit is contained in:
Joel Dice 2008-04-09 13:08:13 -06:00
parent ebffc5852c
commit 2d6eebf4d1
9 changed files with 461 additions and 175 deletions

View File

@ -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)
{

View File

@ -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() {

View File

@ -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;

View File

@ -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);
}

View File

@ -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)

View File

@ -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 {

View File

@ -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)
{

View File

@ -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);
}

View File

@ -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)
{