mirror of
https://github.com/corda/corda.git
synced 2025-01-31 16:35:43 +00:00
more progress on general stack tracing
This commit is contained in:
parent
ebffc5852c
commit
2d6eebf4d1
168
src/compile.cpp
168
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
|
void
|
||||||
pushReturnValue(MyThread* t, Frame* frame, unsigned code)
|
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
|
void
|
||||||
compileDirectInvoke(MyThread* t, Frame* frame, object target)
|
compileDirectInvoke(MyThread* t, Frame* frame, object target)
|
||||||
{
|
{
|
||||||
Compiler* c = frame->c;
|
Compiler* c = frame->c;
|
||||||
|
|
||||||
|
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->alignedCall
|
||||||
(c->constant
|
(c->constant
|
||||||
(reinterpret_cast<intptr_t>
|
(reinterpret_cast<intptr_t>
|
||||||
(&singletonBody(t, methodCompiled(t, target), 0))),
|
(&singletonBody(t, defaultCompiled(t), 0))),
|
||||||
frame->trace(target, false));
|
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));
|
frame->pop(methodParameterFootprint(t, target));
|
||||||
|
|
||||||
@ -1673,7 +1701,8 @@ handleExit(MyThread* t, Frame* frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
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)];
|
uintptr_t stackMap[stackMapSizeInWords(t, initialFrame->context->method)];
|
||||||
Frame myFrame(initialFrame, stackMap);
|
Frame myFrame(initialFrame, stackMap);
|
||||||
@ -1694,6 +1723,15 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
|
|
||||||
frame->startLogicalIp(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));
|
// fprintf(stderr, "ip: %d map: %ld\n", ip, *(frame->map));
|
||||||
|
|
||||||
unsigned instruction = codeBody(t, code, ip++);
|
unsigned instruction = codeBody(t, code, ip++);
|
||||||
@ -1717,8 +1755,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
c->cmp4(c->constant(0), index);
|
c->cmp4(c->constant(0), index);
|
||||||
c->jl(throw_);
|
c->jl(throw_);
|
||||||
|
|
||||||
c->cmp4(c->memory(array, ArrayLength, 0, 1, frame->trace(0, false)),
|
c->cmp4(c->memory(array, ArrayLength, 0, 1), index);
|
||||||
index);
|
|
||||||
c->jl(load);
|
c->jl(load);
|
||||||
|
|
||||||
c->mark(throw_);
|
c->mark(throw_);
|
||||||
@ -1791,8 +1828,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
c->cmp4(c->constant(0), index);
|
c->cmp4(c->constant(0), index);
|
||||||
c->jl(throw_);
|
c->jl(throw_);
|
||||||
|
|
||||||
c->cmp4(c->memory(array, ArrayLength, 0, 1, frame->trace(0, false)),
|
c->cmp4(c->memory(array, ArrayLength, 0, 1), index);
|
||||||
index);
|
|
||||||
c->jl(store);
|
c->jl(store);
|
||||||
|
|
||||||
c->mark(throw_);
|
c->mark(throw_);
|
||||||
@ -1906,8 +1942,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
|
|
||||||
case arraylength: {
|
case arraylength: {
|
||||||
Operand* array = frame->popObject();
|
Operand* array = frame->popObject();
|
||||||
frame->pushInt4
|
frame->pushInt4(c->memory(array, ArrayLength, 0, 1));
|
||||||
(c->memory(array, ArrayLength, 0, 1, frame->trace(0, false)));
|
|
||||||
c->release(array);
|
c->release(array);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -2322,43 +2357,32 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
table = frame->popObject();
|
table = frame->popObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceElement* trace = 0;
|
|
||||||
if (instruction == getfield) {
|
|
||||||
trace = frame->trace(0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (fieldCode(t, field)) {
|
switch (fieldCode(t, field)) {
|
||||||
case ByteField:
|
case ByteField:
|
||||||
case BooleanField:
|
case BooleanField:
|
||||||
frame->pushInt1
|
frame->pushInt1(c->memory(table, fieldOffset(t, field), 0, 1));
|
||||||
(c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CharField:
|
case CharField:
|
||||||
frame->pushInt2z
|
frame->pushInt2z(c->memory(table, fieldOffset(t, field), 0, 1));
|
||||||
(c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ShortField:
|
case ShortField:
|
||||||
frame->pushInt2
|
frame->pushInt2(c->memory(table, fieldOffset(t, field), 0, 1));
|
||||||
(c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FloatField:
|
case FloatField:
|
||||||
case IntField:
|
case IntField:
|
||||||
frame->pushInt4
|
frame->pushInt4(c->memory(table, fieldOffset(t, field), 0, 1));
|
||||||
(c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DoubleField:
|
case DoubleField:
|
||||||
case LongField:
|
case LongField:
|
||||||
frame->pushLong
|
frame->pushLong(c->memory(table, fieldOffset(t, field), 0, 1));
|
||||||
(c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ObjectField:
|
case ObjectField:
|
||||||
frame->pushObject
|
frame->pushObject(c->memory(table, fieldOffset(t, field), 0, 1));
|
||||||
(c->memory(table, fieldOffset(t, field), 0, 1, trace));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -2723,7 +2747,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip)
|
|||||||
Operand* instance = c->stack(frame->stack, parameterFootprint - 1);
|
Operand* instance = c->stack(frame->stack, parameterFootprint - 1);
|
||||||
Operand* class_ = c->temporary();
|
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_);
|
and_(c, c->constant(PointerMask), class_);
|
||||||
|
|
||||||
c->call(c->memory(class_, offset, 0, 1), frame->trace(target, true));
|
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();
|
table = frame->popObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
TraceElement* trace = 0;
|
|
||||||
if (instruction == putfield and fieldCode(t, field) != ObjectField) {
|
|
||||||
trace = frame->trace(0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (fieldCode(t, field)) {
|
switch (fieldCode(t, field)) {
|
||||||
case ByteField:
|
case ByteField:
|
||||||
case BooleanField:
|
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;
|
break;
|
||||||
|
|
||||||
case CharField:
|
case CharField:
|
||||||
case ShortField:
|
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;
|
break;
|
||||||
|
|
||||||
case FloatField:
|
case FloatField:
|
||||||
case IntField:
|
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;
|
break;
|
||||||
|
|
||||||
case DoubleField:
|
case DoubleField:
|
||||||
case LongField:
|
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;
|
break;
|
||||||
|
|
||||||
case ObjectField:
|
case ObjectField:
|
||||||
@ -3931,7 +3950,7 @@ compile(MyThread* t, Context* context)
|
|||||||
frame2.clear(localSize(t, context->method) + i);
|
frame2.clear(localSize(t, context->method) + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
compile(t, &frame2, exceptionHandlerIp(eh));
|
compile(t, &frame2, exceptionHandlerIp(eh), true);
|
||||||
if (UNLIKELY(t->exception)) return 0;
|
if (UNLIKELY(t->exception)) return 0;
|
||||||
|
|
||||||
eventIndex = calculateFrameMaps(t, context, 0, eventIndex);
|
eventIndex = calculateFrameMaps(t, context, 0, eventIndex);
|
||||||
@ -4519,6 +4538,28 @@ invoke(Thread* thread, object method, ArgumentList* arguments)
|
|||||||
return r;
|
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 {
|
class SegFaultHandler: public System::SignalHandler {
|
||||||
public:
|
public:
|
||||||
SegFaultHandler(): m(0) { }
|
SegFaultHandler(): m(0) { }
|
||||||
@ -4533,6 +4574,9 @@ class SegFaultHandler: public System::SignalHandler {
|
|||||||
t->ip = *ip;
|
t->ip = *ip;
|
||||||
t->base = *base;
|
t->base = *base;
|
||||||
t->stack = *stack;
|
t->stack = *stack;
|
||||||
|
|
||||||
|
ensure(t, FixedSizeOfNullPointerException + traceSize(t));
|
||||||
|
|
||||||
t->exception = makeNullPointerException(t);
|
t->exception = makeNullPointerException(t);
|
||||||
|
|
||||||
findUnwindTarget(t, ip, base, stack);
|
findUnwindTarget(t, ip, base, stack);
|
||||||
@ -4831,6 +4875,46 @@ class MyProcessor: public Processor {
|
|||||||
allocator->free(this, sizeof(*this), false);
|
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;
|
System* s;
|
||||||
Allocator* allocator;
|
Allocator* allocator;
|
||||||
object defaultCompiled;
|
object defaultCompiled;
|
||||||
@ -4884,6 +4968,18 @@ processor(MyThread* t)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
defaultCompiled(MyThread* t)
|
||||||
|
{
|
||||||
|
return processor(t)->getDefaultCompiled(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
object
|
||||||
|
nativeCompiled(MyThread* t)
|
||||||
|
{
|
||||||
|
return processor(t)->getNativeCompiled(t);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
compile(MyThread* t, object method)
|
compile(MyThread* t, object method)
|
||||||
{
|
{
|
||||||
|
@ -326,7 +326,7 @@ register_(Context* c, Register = NoRegister, Register = NoRegister);
|
|||||||
|
|
||||||
MemoryOperand*
|
MemoryOperand*
|
||||||
memory(Context* c, MyOperand* base, int displacement,
|
memory(Context* c, MyOperand* base, int displacement,
|
||||||
MyOperand* index, unsigned scale, Compiler::TraceHandler* traceHandler);
|
MyOperand* index, unsigned scale);
|
||||||
|
|
||||||
class MyOperand: public Operand {
|
class MyOperand: public Operand {
|
||||||
public:
|
public:
|
||||||
@ -630,17 +630,15 @@ class AbsoluteOperand: public MyOperand {
|
|||||||
class MemoryOperand: public MyOperand {
|
class MemoryOperand: public MyOperand {
|
||||||
public:
|
public:
|
||||||
MemoryOperand(MyOperand* base, int displacement, MyOperand* index,
|
MemoryOperand(MyOperand* base, int displacement, MyOperand* index,
|
||||||
unsigned scale, Compiler::TraceHandler* traceHandler):
|
unsigned scale):
|
||||||
base(base),
|
base(base),
|
||||||
displacement(displacement),
|
displacement(displacement),
|
||||||
index(index),
|
index(index),
|
||||||
scale(scale),
|
scale(scale)
|
||||||
traceHandler(traceHandler)
|
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
MemoryOperand* high(Context* c) {
|
MemoryOperand* high(Context* c) {
|
||||||
return memory
|
return memory(c, base, displacement + BytesPerWord, index, scale);
|
||||||
(c, base, displacement + BytesPerWord, index, scale, traceHandler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Register asRegister(Context*);
|
virtual Register asRegister(Context*);
|
||||||
@ -670,7 +668,6 @@ class MemoryOperand: public MyOperand {
|
|||||||
int displacement;
|
int displacement;
|
||||||
MyOperand* index;
|
MyOperand* index;
|
||||||
unsigned scale;
|
unsigned scale;
|
||||||
Compiler::TraceHandler* traceHandler;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CodePromiseTask: public Task {
|
class CodePromiseTask: public Task {
|
||||||
@ -722,10 +719,10 @@ register_(Context* c, Register v, Register h)
|
|||||||
|
|
||||||
MemoryOperand*
|
MemoryOperand*
|
||||||
memory(Context* c, MyOperand* base, int displacement,
|
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)))
|
return new (c->zone->allocate(sizeof(MemoryOperand)))
|
||||||
MemoryOperand(base, displacement, index, scale, traceHandler);
|
MemoryOperand(base, displacement, index, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
RegisterOperand*
|
RegisterOperand*
|
||||||
@ -1038,8 +1035,7 @@ pushed(Context* c, MyStack* stack)
|
|||||||
int index = (stack ? stack->index + 1 : 0);
|
int index = (stack ? stack->index + 1 : 0);
|
||||||
|
|
||||||
MyOperand* value = memory
|
MyOperand* value = memory
|
||||||
(c, register_(c, rbp), - (c->reserved + index + 1) * BytesPerWord, 0, 1,
|
(c, register_(c, rbp), - (c->reserved + index + 1) * BytesPerWord, 0, 1);
|
||||||
0);
|
|
||||||
|
|
||||||
stack = new (c->zone->allocate(sizeof(MyStack)))
|
stack = new (c->zone->allocate(sizeof(MyStack)))
|
||||||
MyStack(value, index, stack);
|
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);
|
Register r = b->base->asRegister(c);
|
||||||
int index = b->index ? b->index->asRegister(c) : -1;
|
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) {
|
if (rex) {
|
||||||
::rex(c);
|
::rex(c);
|
||||||
}
|
}
|
||||||
@ -1201,12 +1191,6 @@ encode2(Context* c, uint16_t instruction, int a, MemoryOperand* b, bool rex)
|
|||||||
Register r = b->base->asRegister(c);
|
Register r = b->base->asRegister(c);
|
||||||
int index = b->index ? b->index->asRegister(c) : -1;
|
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) {
|
if (rex) {
|
||||||
::rex(c);
|
::rex(c);
|
||||||
}
|
}
|
||||||
@ -1572,7 +1556,7 @@ RegisterOperand::accept(Context* c, Operation op,
|
|||||||
|
|
||||||
RegisterOperand* tmp = temporary(c);
|
RegisterOperand* tmp = temporary(c);
|
||||||
tmp->accept(c, mov, ::value(c, operand));
|
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);
|
tmp->release(c);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -1581,7 +1565,7 @@ RegisterOperand::accept(Context* c, Operation op,
|
|||||||
assert(c, BytesPerWord == 8 or op == mov4); // todo
|
assert(c, BytesPerWord == 8 or op == mov4); // todo
|
||||||
|
|
||||||
accept(c, mov, ::value(c, operand));
|
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;
|
} break;
|
||||||
|
|
||||||
default: abort(c);
|
default: abort(c);
|
||||||
@ -1759,7 +1743,7 @@ absoluteApply(Context* c, MyOperand::Operation op,
|
|||||||
{
|
{
|
||||||
RegisterOperand* tmp = temporary(c);
|
RegisterOperand* tmp = temporary(c);
|
||||||
tmp->accept(c, MyOperand::mov, value(c, operand));
|
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);
|
tmp->release(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2797,11 +2781,10 @@ class MyCompiler: public Compiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual Operand* memory(Operand* base, int displacement,
|
virtual Operand* memory(Operand* base, int displacement,
|
||||||
Operand* index, unsigned scale,
|
Operand* index, unsigned scale)
|
||||||
TraceHandler* trace)
|
|
||||||
{
|
{
|
||||||
return ::memory(&c, static_cast<MyOperand*>(base), displacement,
|
return ::memory(&c, static_cast<MyOperand*>(base), displacement,
|
||||||
static_cast<MyOperand*>(index), scale, trace);
|
static_cast<MyOperand*>(index), scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void prologue() {
|
virtual void prologue() {
|
||||||
|
@ -51,8 +51,7 @@ class Compiler {
|
|||||||
virtual Operand* memory(Operand* base,
|
virtual Operand* memory(Operand* base,
|
||||||
int displacement = 0,
|
int displacement = 0,
|
||||||
Operand* index = 0,
|
Operand* index = 0,
|
||||||
unsigned scale = 1,
|
unsigned scale = 1) = 0;
|
||||||
TraceHandler* traceHandler = 0) = 0;
|
|
||||||
|
|
||||||
virtual Operand* stack() = 0;
|
virtual Operand* stack() = 0;
|
||||||
virtual Operand* base() = 0;
|
virtual Operand* base() = 0;
|
||||||
|
@ -501,6 +501,13 @@ postCollect(Thread* t)
|
|||||||
t->heapOffset = 0;
|
t->heapOffset = 0;
|
||||||
t->heapIndex = 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) {
|
for (Thread* c = t->child; c; c = c->peer) {
|
||||||
postCollect(c);
|
postCollect(c);
|
||||||
}
|
}
|
||||||
@ -1740,7 +1747,10 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
|||||||
runnable(this),
|
runnable(this),
|
||||||
defaultHeap(static_cast<uintptr_t*>
|
defaultHeap(static_cast<uintptr_t*>
|
||||||
(m->heap->allocate(HeapSizeInBytes, false))),
|
(m->heap->allocate(HeapSizeInBytes, false))),
|
||||||
heap(defaultHeap)
|
heap(defaultHeap),
|
||||||
|
backupHeap(0),
|
||||||
|
backupHeapIndex(0),
|
||||||
|
backupHeapSizeInWords(0)
|
||||||
#ifdef VM_STRESS
|
#ifdef VM_STRESS
|
||||||
, stress(false)
|
, stress(false)
|
||||||
#endif // VM_STRESS
|
#endif // VM_STRESS
|
||||||
@ -2043,6 +2053,16 @@ object
|
|||||||
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
||||||
unsigned sizeInBytes, bool executable, bool objectMask)
|
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);
|
ACQUIRE_RAW(t, t->m->stateLock);
|
||||||
|
|
||||||
while (t->m->exclusive and t->m->exclusive != t) {
|
while (t->m->exclusive and t->m->exclusive != t) {
|
||||||
@ -2058,7 +2078,7 @@ allocate3(Thread* t, Allocator* allocator, Machine::AllocationType type,
|
|||||||
t->heap = 0;
|
t->heap = 0;
|
||||||
}
|
}
|
||||||
} else if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
} else if (t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||||
>= Thread::HeapSizeInWords)
|
> Thread::HeapSizeInWords)
|
||||||
{
|
{
|
||||||
t->heap = 0;
|
t->heap = 0;
|
||||||
if (t->m->heapPoolIndex < Machine::HeapPoolSize) {
|
if (t->m->heapPoolIndex < Machine::HeapPoolSize) {
|
||||||
@ -2839,7 +2859,7 @@ makeTrace(Thread* t, Processor::StackWalker* walker)
|
|||||||
}
|
}
|
||||||
|
|
||||||
object
|
object
|
||||||
makeTrace(Thread* t)
|
makeTrace(Thread* t, Thread* target)
|
||||||
{
|
{
|
||||||
class Visitor: public Processor::StackVisitor {
|
class Visitor: public Processor::StackVisitor {
|
||||||
public:
|
public:
|
||||||
@ -2854,7 +2874,7 @@ makeTrace(Thread* t)
|
|||||||
object trace;
|
object trace;
|
||||||
} v(t);
|
} v(t);
|
||||||
|
|
||||||
t->m->processor->walkStack(t, &v);
|
t->m->processor->walkStack(target, &v);
|
||||||
|
|
||||||
return v.trace ? v.trace : makeArray(t, 0, true);
|
return v.trace ? v.trace : makeArray(t, 0, true);
|
||||||
}
|
}
|
||||||
|
@ -1288,6 +1288,9 @@ class Thread {
|
|||||||
Runnable runnable;
|
Runnable runnable;
|
||||||
uintptr_t* defaultHeap;
|
uintptr_t* defaultHeap;
|
||||||
uintptr_t* heap;
|
uintptr_t* heap;
|
||||||
|
uintptr_t* backupHeap;
|
||||||
|
unsigned backupHeapIndex;
|
||||||
|
unsigned backupHeapSizeInWords;
|
||||||
#ifdef VM_STRESS
|
#ifdef VM_STRESS
|
||||||
bool stress;
|
bool stress;
|
||||||
#endif // VM_STRESS
|
#endif // VM_STRESS
|
||||||
@ -1426,6 +1429,20 @@ expect(Thread* t, bool v)
|
|||||||
expect(t->m->system, 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
|
object
|
||||||
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask);
|
allocate2(Thread* t, unsigned sizeInBytes, bool objectMask);
|
||||||
|
|
||||||
@ -1448,7 +1465,7 @@ allocate(Thread* t, unsigned sizeInBytes, bool objectMask)
|
|||||||
stress(t);
|
stress(t);
|
||||||
|
|
||||||
if (UNLIKELY(t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
if (UNLIKELY(t->heapIndex + ceiling(sizeInBytes, BytesPerWord)
|
||||||
>= Thread::HeapSizeInWords
|
> Thread::HeapSizeInWords
|
||||||
or t->m->exclusive))
|
or t->m->exclusive))
|
||||||
{
|
{
|
||||||
return allocate2(t, sizeInBytes, objectMask);
|
return allocate2(t, sizeInBytes, objectMask);
|
||||||
@ -1527,7 +1544,13 @@ object
|
|||||||
makeTrace(Thread* t, Processor::StackWalker* walker);
|
makeTrace(Thread* t, Processor::StackWalker* walker);
|
||||||
|
|
||||||
object
|
object
|
||||||
makeTrace(Thread* t);
|
makeTrace(Thread* t, Thread* target);
|
||||||
|
|
||||||
|
inline object
|
||||||
|
makeTrace(Thread* t)
|
||||||
|
{
|
||||||
|
return makeTrace(t, t);
|
||||||
|
}
|
||||||
|
|
||||||
inline object
|
inline object
|
||||||
makeRuntimeException(Thread* t, object message)
|
makeRuntimeException(Thread* t, object message)
|
||||||
|
194
src/posix.cpp
194
src/posix.cpp
@ -35,9 +35,6 @@ using namespace vm;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
System::SignalHandler* segFaultHandler = 0;
|
|
||||||
struct sigaction oldSegFaultHandler;
|
|
||||||
|
|
||||||
class MutexResource {
|
class MutexResource {
|
||||||
public:
|
public:
|
||||||
MutexResource(pthread_mutex_t& m): m(&m) {
|
MutexResource(pthread_mutex_t& m): m(&m) {
|
||||||
@ -52,12 +49,22 @@ class MutexResource {
|
|||||||
pthread_mutex_t* m;
|
pthread_mutex_t* m;
|
||||||
};
|
};
|
||||||
|
|
||||||
const int InterruptSignal = SIGUSR2;
|
const int VisitSignal = SIGUSR1;
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
const int SegFaultSignal = SIGBUS;
|
const int SegFaultSignal = SIGBUS;
|
||||||
#else
|
#else
|
||||||
const int SegFaultSignal = SIGSEGV;
|
const int SegFaultSignal = SIGSEGV;
|
||||||
#endif
|
#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__
|
#ifdef __x86_64__
|
||||||
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP])
|
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP])
|
||||||
@ -86,41 +93,7 @@ const int SegFaultSignal = SIGSEGV;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void
|
void
|
||||||
handleSignal(int signal, siginfo_t* info, void* context)
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
void*
|
||||||
run(void* r)
|
run(void* r)
|
||||||
@ -547,15 +520,33 @@ class MySystem: public System {
|
|||||||
System::Library* next_;
|
System::Library* next_;
|
||||||
};
|
};
|
||||||
|
|
||||||
MySystem() {
|
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;
|
struct sigaction sa;
|
||||||
memset(&sa, 0, sizeof(struct sigaction));
|
memset(&sa, 0, sizeof(struct sigaction));
|
||||||
sigemptyset(&(sa.sa_mask));
|
sigemptyset(&(sa.sa_mask));
|
||||||
sa.sa_flags = SA_SIGINFO;
|
sa.sa_flags = SA_SIGINFO;
|
||||||
sa.sa_sigaction = handleSignal;
|
sa.sa_sigaction = handleSignal;
|
||||||
|
|
||||||
int rv UNUSED = sigaction(InterruptSignal, &sa, 0);
|
return sigaction(signals[index], &sa, oldHandlers + index);
|
||||||
expect(this, rv == 0);
|
} else if (handlers[index]) {
|
||||||
|
handlers[index] = 0;
|
||||||
|
return sigaction(signals[index], oldHandlers + index, 0);
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* tryAllocate(unsigned size, bool executable) {
|
virtual void* tryAllocate(unsigned size, bool executable) {
|
||||||
@ -625,22 +616,32 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual Status handleSegFault(SignalHandler* handler) {
|
virtual Status handleSegFault(SignalHandler* handler) {
|
||||||
if (handler) {
|
return registerHandler(handler, SegFaultSignalIndex);
|
||||||
segFaultHandler = handler;
|
|
||||||
|
|
||||||
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,
|
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
||||||
@ -754,10 +755,89 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
|
visitLock->dispose();
|
||||||
|
|
||||||
|
registerHandler(0, InterruptSignalIndex);
|
||||||
|
registerHandler(0, VisitSignalIndex);
|
||||||
|
system = 0;
|
||||||
|
|
||||||
::free(this);
|
::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
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
|
26
src/system.h
26
src/system.h
@ -34,6 +34,12 @@ class System {
|
|||||||
virtual void dispose() = 0;
|
virtual void dispose() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ThreadVisitor {
|
||||||
|
public:
|
||||||
|
virtual ~ThreadVisitor() { }
|
||||||
|
virtual void visit(void* ip, void* base, void* stack) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class Runnable {
|
class Runnable {
|
||||||
public:
|
public:
|
||||||
virtual ~Runnable() { }
|
virtual ~Runnable() { }
|
||||||
@ -99,6 +105,21 @@ class System {
|
|||||||
void** thread) = 0;
|
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 ~System() { }
|
||||||
|
|
||||||
virtual bool success(Status) = 0;
|
virtual bool success(Status) = 0;
|
||||||
@ -110,6 +131,8 @@ class System {
|
|||||||
virtual Status make(Monitor**) = 0;
|
virtual Status make(Monitor**) = 0;
|
||||||
virtual Status make(Local**) = 0;
|
virtual Status make(Local**) = 0;
|
||||||
virtual Status handleSegFault(SignalHandler* handler) = 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,
|
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
||||||
unsigned count, unsigned size,
|
unsigned count, unsigned size,
|
||||||
unsigned returnType) = 0;
|
unsigned returnType) = 0;
|
||||||
@ -123,6 +146,9 @@ class System {
|
|||||||
virtual void dispose() = 0;
|
virtual void dispose() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ACQUIRE_MONITOR(t, m) \
|
||||||
|
System::MonitorResource MAKE_NAME(monitorResource_) (t, m)
|
||||||
|
|
||||||
inline void NO_RETURN
|
inline void NO_RETURN
|
||||||
abort(System* s)
|
abort(System* s)
|
||||||
{
|
{
|
||||||
|
@ -1507,7 +1507,7 @@ writeOffset(Output* out, Object* offset, bool allocationStyle = false)
|
|||||||
out->write("length");
|
out->write("length");
|
||||||
} else {
|
} else {
|
||||||
out->write(typeName(memberOwner(o)));
|
out->write(typeName(memberOwner(o)));
|
||||||
out->write(capitalize("length"));
|
out->write("Length");
|
||||||
out->write("(o)");
|
out->write("(o)");
|
||||||
}
|
}
|
||||||
out->write(" * ");
|
out->write(" * ");
|
||||||
@ -1762,6 +1762,49 @@ typeFixedSize(Object* type)
|
|||||||
return length;
|
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*
|
const char*
|
||||||
obfuscate(const char* s)
|
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
|
uint32_t
|
||||||
typeObjectMask(Object* type)
|
typeObjectMask(Object* type)
|
||||||
{
|
{
|
||||||
@ -2274,6 +2299,7 @@ main(int ac, char** av)
|
|||||||
|
|
||||||
writePods(&out, declarations);
|
writePods(&out, declarations);
|
||||||
writeAccessors(&out, declarations);
|
writeAccessors(&out, declarations);
|
||||||
|
writeSizes(&out, declarations);
|
||||||
writeInitializerDeclarations(&out, declarations);
|
writeInitializerDeclarations(&out, declarations);
|
||||||
writeConstructorDeclarations(&out, declarations);
|
writeConstructorDeclarations(&out, declarations);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,23 @@ using namespace vm;
|
|||||||
|
|
||||||
namespace {
|
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;
|
System::SignalHandler* segFaultHandler = 0;
|
||||||
LPTOP_LEVEL_EXCEPTION_FILTER oldSegFaultHandler = 0;
|
LPTOP_LEVEL_EXCEPTION_FILTER oldSegFaultHandler = 0;
|
||||||
|
|
||||||
@ -43,23 +60,6 @@ handleException(LPEXCEPTION_POINTERS e)
|
|||||||
return EXCEPTION_CONTINUE_SEARCH;
|
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
|
DWORD WINAPI
|
||||||
run(void* r)
|
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,
|
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
||||||
unsigned count, unsigned size, unsigned returnType)
|
unsigned count, unsigned size, unsigned returnType)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user