diff --git a/src/compile.cpp b/src/compile.cpp index 1c17a816d7..e48f47404e 100644 --- a/src/compile.cpp +++ b/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 - (&singletonBody(t, methodCompiled(t, target), 0))), - frame->trace(target, false)); + if (methodFlags(t, target) & ACC_NATIVE) { + c->call + (c->constant + (reinterpret_cast + (&singletonBody(t, nativeCompiled(t), 0))), + frame->trace(target, false)); + } else if (methodCompiled(t, target) == defaultCompiled(t)) { + c->alignedCall + (c->constant + (reinterpret_cast + (&singletonBody(t, defaultCompiled(t), 0))), + frame->trace(target, false)); + } else { + c->call + (c->constant + (reinterpret_cast + (&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(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(vmt); + MyThread* target = static_cast(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) { diff --git a/src/compiler.cpp b/src/compiler.cpp index 6aa3dad373..56c7567bc8 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -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 - (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 - (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(base), displacement, - static_cast(index), scale, trace); + static_cast(index), scale); } virtual void prologue() { diff --git a/src/compiler.h b/src/compiler.h index 3db925318f..4efa780b2d 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -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; diff --git a/src/machine.cpp b/src/machine.cpp index ed53790c60..a06fd154ea 100644 --- a/src/machine.cpp +++ b/src/machine.cpp @@ -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 (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(t->backupHeap + t->backupHeapIndex); + t->backupHeapIndex += ceiling(sizeInBytes, BytesPerWord); + cast(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); } diff --git a/src/machine.h b/src/machine.h index 2197de677e..d6d95c920b 100644 --- a/src/machine.h +++ b/src/machine.h @@ -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 + (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) diff --git a/src/posix.cpp b/src/posix.cpp index 21ad14d866..46571ff5f4 100644 --- a/src/posix.cpp +++ b/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(context); - - void* ip = reinterpret_cast(IP_REGISTER(c)); - void* base = reinterpret_cast(BASE_REGISTER(c)); - void* stack = reinterpret_cast(STACK_REGISTER(c)); - void* thread = reinterpret_cast(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(st); + Thread* target = static_cast(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(context); + + void* ip = reinterpret_cast(IP_REGISTER(c)); + void* base = reinterpret_cast(BASE_REGISTER(c)); + void* stack = reinterpret_cast(STACK_REGISTER(c)); + void* thread = reinterpret_cast(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 { diff --git a/src/system.h b/src/system.h index 3b45b1b168..c2f5890530 100644 --- a/src/system.h +++ b/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) { diff --git a/src/type-generator.cpp b/src/type-generator.cpp index 4aca763bc6..616d3458e2 100644 --- a/src/type-generator.cpp +++ b/src/type-generator.cpp @@ -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); } diff --git a/src/windows.cpp b/src/windows.cpp index 650edf1008..2cbca5cbf2 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -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(st); + Thread* target = static_cast(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(context->Eip), + reinterpret_cast(context->Ebp), + reinterpret_cast(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) {