diff --git a/src/compile.cpp b/src/compile.cpp index 3268e8c645..686d68e1f0 100644 --- a/src/compile.cpp +++ b/src/compile.cpp @@ -1017,14 +1017,20 @@ class Context { } } - virtual intptr_t getThunk(TernaryOperation op, unsigned size, unsigned) { + virtual intptr_t getThunk(TernaryOperation op, unsigned size, unsigned, + bool* threadParameter) + { + *threadParameter = false; + if (size == 8) { switch (op) { case Divide: + *threadParameter = true; return local::getThunk(t, divideLongThunk); case Remainder: - return local::getThunk(t, moduloLongThunk); + *threadParameter = true; + return local::getThunk(t, moduloLongThunk); case FloatAdd: return local::getThunk(t, addDoubleThunk); @@ -1061,9 +1067,11 @@ class Context { assert(t, size == 4); switch (op) { case Divide: + *threadParameter = true; return local::getThunk(t, divideIntThunk); case Remainder: + *threadParameter = true; return local::getThunk(t, moduloIntThunk); case FloatAdd: @@ -2358,26 +2366,47 @@ absoluteInt(int32_t a) } int64_t -divideLong(int64_t b, int64_t a) +divideLong(MyThread* t, int64_t b, int64_t a) { - return a / b; + if (LIKELY(b)) { + return a / b; + } else { + t->exception = makeThrowable(t, Machine::ArithmeticExceptionType); + unwind(t); + } } int64_t -divideInt(int32_t b, int32_t a) +divideInt(MyThread* t, int32_t b, int32_t a) { - return a / b; + if (LIKELY(b)) { + return a / b; + } else { + t->exception = makeThrowable(t, Machine::ArithmeticExceptionType); + unwind(t); + } } int64_t -moduloLong(int64_t b, int64_t a) +moduloLong(MyThread* t, int64_t b, int64_t a) { - return a % b; + if (LIKELY(b)) { + return a % b; + } else { + t->exception = makeThrowable(t, Machine::ArithmeticExceptionType); + unwind(t); + } } int64_t -moduloInt(int32_t b, int32_t a) { - return a % b; +moduloInt(MyThread* t, int32_t b, int32_t a) +{ + if (LIKELY(b)) { + return a % b; + } else { + t->exception = makeThrowable(t, Machine::ArithmeticExceptionType); + unwind(t); + } } uint64_t @@ -3949,6 +3978,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case idiv: { Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); + + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + frame->trace(0, 0); + } + frame->pushInt(c->div(4, a, b)); } break; @@ -4262,6 +4297,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case irem: { Compiler::Operand* a = frame->popInt(); Compiler::Operand* b = frame->popInt(); + + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + frame->trace(0, 0); + } + frame->pushInt(c->rem(4, a, b)); } break; @@ -4459,6 +4500,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case ldiv_: { Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); + + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + frame->trace(0, 0); + } + frame->pushLong(c->div(8, a, b)); } break; @@ -4564,6 +4611,12 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip, case lrem: { Compiler::Operand* a = frame->popLong(); Compiler::Operand* b = frame->popLong(); + + if (inTryBlock(t, code, ip - 1)) { + c->saveLocals(); + frame->trace(0, 0); + } + frame->pushLong(c->rem(8, a, b)); } break; @@ -7186,9 +7239,10 @@ invoke(Thread* thread, object method, ArgumentList* arguments) return r; } -class SegFaultHandler: public System::SignalHandler { +class SignalHandler: public System::SignalHandler { public: - SegFaultHandler(): m(0) { } + SignalHandler(Machine::Type type, Machine::Root root, unsigned fixedSize): + m(0), type(type), root(root), fixedSize(fixedSize) { } virtual bool handleSignal(void** ip, void** base, void** stack, void** thread) @@ -7204,14 +7258,14 @@ class SegFaultHandler: public System::SignalHandler { static_cast(*stack) - t->arch->frameReturnAddressSize(), *base, t->continuation, t->trace); - if (ensure(t, FixedSizeOfNullPointerException + traceSize(t))) { + if (ensure(t, fixedSize + traceSize(t))) { atomicOr(&(t->flags), Thread::TracingFlag); - t->exception = makeThrowable(t, Machine::NullPointerExceptionType); + t->exception = makeThrowable(t, type); atomicAnd(&(t->flags), ~Thread::TracingFlag); } else { - // not enough memory available for a new NPE and stack trace - // -- use a preallocated instance instead - t->exception = root(t, Machine::NullPointerException); + // not enough memory available for a new exception and stack + // trace -- use a preallocated instance instead + t->exception = vm::root(t, root); } // printTrace(t, t->exception); @@ -7235,6 +7289,9 @@ class SegFaultHandler: public System::SignalHandler { } Machine* m; + Machine::Type type; + Machine::Root root; + unsigned fixedSize; }; bool @@ -7289,6 +7346,12 @@ class MyProcessor: public Processor { allocator(allocator), roots(0), bootImage(0), + segFaultHandler(Machine::NullPointerExceptionType, + Machine::NullPointerException, + FixedSizeOfNullPointerException), + divideByZeroHandler(Machine::ArithmeticExceptionType, + Machine::ArithmeticException, + FixedSizeOfArithmeticException), codeAllocator(s, 0, 0), callTableSize(0), useNativeFeatures(useNativeFeatures) @@ -7744,6 +7807,10 @@ class MyProcessor: public Processor { segFaultHandler.m = t->m; expect(t, t->m->system->success (t->m->system->handleSegFault(&segFaultHandler))); + + divideByZeroHandler.m = t->m; + expect(t, t->m->system->success + (t->m->system->handleDivideByZero(÷ByZeroHandler))); } virtual void callWithCurrentContinuation(Thread* t, object receiver) { @@ -7798,7 +7865,8 @@ class MyProcessor: public Processor { Allocator* allocator; object roots; BootImage* bootImage; - SegFaultHandler segFaultHandler; + SignalHandler segFaultHandler; + SignalHandler divideByZeroHandler; FixedAllocator codeAllocator; ThunkCollection thunks; ThunkCollection bootThunks; diff --git a/src/compiler.cpp b/src/compiler.cpp index 1cbc55bc75..ed918ae7b2 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -4336,6 +4336,19 @@ loadLocal(Context* c, unsigned footprint, unsigned index) return c->locals[index].value; } +Value* +register_(Context* c, int number) +{ + assert(c, (1 << number) & (c->arch->generalRegisterMask() + | c->arch->floatRegisterMask())); + + Site* s = registerSite(c, number); + ValueType type = ((1 << number) & c->arch->floatRegisterMask()) + ? ValueFloat: ValueGeneral; + + return value(c, type, s, s); +} + void appendCombine(Context* c, TernaryOperation type, unsigned firstSize, Value* first, @@ -4349,25 +4362,34 @@ appendCombine(Context* c, TernaryOperation type, uint64_t secondRegisterMask; c->arch->planSource(type, firstSize, &firstTypeMask, &firstRegisterMask, - secondSize, &secondTypeMask, &secondRegisterMask, - resultSize, &thunk); + secondSize, &secondTypeMask, &secondRegisterMask, + resultSize, &thunk); if (thunk) { Stack* oldStack = c->stack; + bool threadParameter; + intptr_t handler = c->client->getThunk + (type, firstSize, resultSize, &threadParameter); + + unsigned stackSize = ceiling(secondSize, BytesPerWord) + + ceiling(firstSize, BytesPerWord); + local::push(c, ceiling(secondSize, BytesPerWord), second); local::push(c, ceiling(firstSize, BytesPerWord), first); + if (threadParameter) { + ++ stackSize; + + local::push(c, 1, register_(c, c->arch->thread())); + } + Stack* argumentStack = c->stack; c->stack = oldStack; appendCall - (c, value - (c, ValueGeneral, constantSite - (c, c->client->getThunk(type, firstSize, resultSize))), - 0, 0, result, resultSize, argumentStack, - ceiling(secondSize, BytesPerWord) + ceiling(firstSize, BytesPerWord), - 0); + (c, value(c, ValueGeneral, constantSite(c, handler)), 0, 0, result, + resultSize, argumentStack, stackSize, 0); } else { append (c, new (c->zone->allocate(sizeof(CombineEvent))) @@ -4792,6 +4814,12 @@ appendBranch(Context* c, TernaryOperation type, unsigned size, Value* first, if (thunk) { Stack* oldStack = c->stack; + bool threadParameter; + intptr_t handler = c->client->getThunk + (type, size, size, &threadParameter); + + assert(c, not threadParameter); + local::push(c, ceiling(size, BytesPerWord), second); local::push(c, ceiling(size, BytesPerWord), first); @@ -4801,9 +4829,8 @@ appendBranch(Context* c, TernaryOperation type, unsigned size, Value* first, Value* result = value(c, ValueGeneral); appendCall (c, value - (c, ValueGeneral, constantSite(c, c->client->getThunk(type, size, 4))), - 0, 0, result, 4, argumentStack, - ceiling(size, BytesPerWord) * 2, 0); + (c, ValueGeneral, constantSite(c, handler)), 0, 0, result, 4, + argumentStack, ceiling(size, BytesPerWord) * 2, 0); appendBranch(c, thunkBranch(c, type), 4, value (c, ValueGeneral, constantSite(c, static_cast(0))), @@ -6167,14 +6194,7 @@ class MyCompiler: public Compiler { } virtual Operand* register_(int number) { - assert(&c, (1 << number) & (c.arch->generalRegisterMask() - | c.arch->floatRegisterMask())); - - Site* s = registerSite(&c, number); - ValueType type = ((1 << number) & c.arch->floatRegisterMask()) - ? ValueFloat: ValueGeneral; - - return value(&c, type, s, s); + return local::register_(&c, number); } Promise* machineIp() { diff --git a/src/compiler.h b/src/compiler.h index 1850baca0b..282941b722 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -30,7 +30,7 @@ class Compiler { virtual intptr_t getThunk(BinaryOperation op, unsigned size, unsigned resultSize) = 0; virtual intptr_t getThunk(TernaryOperation op, unsigned size, - unsigned resultSize) = 0; + unsigned resultSize, bool* threadParameter) = 0; }; static const unsigned Aligned = 1 << 0; diff --git a/src/interpret.cpp b/src/interpret.cpp index bc5cb36898..fd1bbcbcf3 100644 --- a/src/interpret.cpp +++ b/src/interpret.cpp @@ -1665,6 +1665,11 @@ interpret(Thread* t) case idiv: { int32_t b = popInt(t); int32_t a = popInt(t); + + if (UNLIKELY(b == 0)) { + exception = makeThrowable(t, Machine::ArithmeticExceptionType); + goto throw_; + } pushInt(t, a / b); } goto loop; @@ -1968,6 +1973,11 @@ interpret(Thread* t) int32_t b = popInt(t); int32_t a = popInt(t); + if (UNLIKELY(b == 0)) { + exception = makeThrowable(t, Machine::ArithmeticExceptionType); + goto throw_; + } + pushInt(t, a % b); } goto loop; @@ -2187,6 +2197,11 @@ interpret(Thread* t) int64_t b = popLong(t); int64_t a = popLong(t); + if (UNLIKELY(b == 0)) { + exception = makeThrowable(t, Machine::ArithmeticExceptionType); + goto throw_; + } + pushLong(t, a / b); } goto loop; @@ -2269,6 +2284,11 @@ interpret(Thread* t) int64_t b = popLong(t); int64_t a = popLong(t); + if (UNLIKELY(b == 0)) { + exception = makeThrowable(t, Machine::ArithmeticExceptionType); + goto throw_; + } + pushLong(t, a % b); } goto loop; diff --git a/src/jnienv.cpp b/src/jnienv.cpp index 38598a385a..43baf82d92 100644 --- a/src/jnienv.cpp +++ b/src/jnienv.cpp @@ -2035,8 +2035,13 @@ boot(Thread* t) (t, Machine::NullPointerExceptionType)); if (t->exception == 0) { - setRoot(t, Machine::ArrayIndexOutOfBoundsException, - makeThrowable(t, Machine::ArrayIndexOutOfBoundsExceptionType)); + setRoot(t, Machine::ArithmeticException, + makeThrowable(t, Machine::ArithmeticExceptionType)); + + if (t->exception == 0) { + setRoot(t, Machine::ArrayIndexOutOfBoundsException, + makeThrowable(t, Machine::ArrayIndexOutOfBoundsExceptionType)); + } } } diff --git a/src/machine.h b/src/machine.h index d4a381b082..4070c99e80 100644 --- a/src/machine.h +++ b/src/machine.h @@ -1203,6 +1203,7 @@ class Machine { ShutdownHooks, ObjectsToFinalize, NullPointerException, + ArithmeticException, ArrayIndexOutOfBoundsException, VirtualFileFinders, VirtualFiles diff --git a/src/posix.cpp b/src/posix.cpp index b4b833cb62..4439feea01 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -69,14 +69,17 @@ const int AltSegFaultSignal = InvalidSignal; const unsigned AltSegFaultSignalIndex = 3; const int PipeSignal = SIGPIPE; const unsigned PipeSignalIndex = 4; +const int DivideByZeroSignal = SIGFPE; +const unsigned DivideByZeroSignalIndex = 5; const int signals[] = { VisitSignal, SegFaultSignal, InterruptSignal, AltSegFaultSignal, - PipeSignal }; + PipeSignal, + DivideByZeroSignal }; -const unsigned SignalCount = 5; +const unsigned SignalCount = 6; class MySystem; MySystem* system; @@ -530,6 +533,8 @@ class MySystem: public System { expect(this, system == 0); system = this; + memset(handlers, 0, sizeof(handlers)); + registerHandler(&nullHandler, InterruptSignalIndex); registerHandler(&nullHandler, PipeSignalIndex); registerHandler(&nullHandler, VisitSignalIndex); @@ -631,6 +636,10 @@ class MySystem: public System { return s; } + virtual Status handleDivideByZero(SignalHandler* handler) { + return registerHandler(handler, DivideByZeroSignalIndex); + } + virtual Status visit(System::Thread* st, System::Thread* sTarget, ThreadVisitor* visitor) { @@ -847,12 +856,25 @@ handleSignal(int signal, siginfo_t* info, void* context) } break; case SegFaultSignal: - case AltSegFaultSignal: { - if (signal == SegFaultSignal) { + case AltSegFaultSignal: + case DivideByZeroSignal: { + switch (signal) { + case SegFaultSignal: index = SegFaultSignalIndex; - } else { + break; + + case AltSegFaultSignal: index = AltSegFaultSignalIndex; + break; + + case DivideByZeroSignal: + index = DivideByZeroSignalIndex; + break; + + default: + abort(); } + bool jump = system->handlers[index]->handleSignal (&ip, &base, &stack, &thread); diff --git a/src/system.h b/src/system.h index 95e025f433..315f7151d2 100644 --- a/src/system.h +++ b/src/system.h @@ -126,6 +126,7 @@ class System { virtual Status make(Monitor**) = 0; virtual Status make(Local**) = 0; virtual Status handleSegFault(SignalHandler* handler) = 0; + virtual Status handleDivideByZero(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, diff --git a/src/types.def b/src/types.def index b16cd79bf9..8b8d980ffc 100644 --- a/src/types.def +++ b/src/types.def @@ -205,6 +205,8 @@ (type nullPointerException java/lang/NullPointerException) +(type arithmeticException java/lang/ArithmeticException) + (type illegalStateException java/lang/IllegalStateException) (type illegalArgumentException java/lang/IllegalArgumentException) diff --git a/src/windows.cpp b/src/windows.cpp index 52c95f2bd0..b86d2fa99e 100644 --- a/src/windows.cpp +++ b/src/windows.cpp @@ -49,6 +49,11 @@ class MutexResource { HANDLE m; }; +const unsigned SegFaultIndex = 0; +const unsigned DivideByZeroIndex = 1; + +const unsigned HandlerCount = 2; + class MySystem; MySystem* system; @@ -510,17 +515,57 @@ class MySystem: public System { }; MySystem(const char* crashDumpDirectory): - segFaultHandler(0), - oldSegFaultHandler(0), + oldHandler(0), crashDumpDirectory(crashDumpDirectory) { expect(this, system == 0); system = this; + memset(handlers, 0, sizeof(handlers)); + mutex = CreateMutex(0, false, 0); assert(this, mutex); } + bool findHandler() { + for (unsigned i = 0; i < HandlerCount; ++i) { + if (handlers[i]) return true; + } + return false; + } + + int registerHandler(System::SignalHandler* handler, int index) { + if (handler) { + handlers[index] = handler; + + if (oldHandler == 0) { +#ifdef ARCH_x86_32 + oldHandler = SetUnhandledExceptionFilter(handleException); +#elif defined ARCH_x86_64 + AddVectoredExceptionHandler(1, handleException); + oldHandler = reinterpret_cast(1); +#endif + } + + return 0; + } else if (handlers[index]) { + handlers[index] = 0; + + if (not findHandler()) { +#ifdef ARCH_x86_32 + SetUnhandledExceptionFilter(oldHandler); + oldHandler = 0; +#elif defined ARCH_x86_64 + // do nothing, handlers are never "unregistered" anyway +#endif + } + + return 0; + } else { + return 1; + } + } + virtual void* tryAllocate(unsigned sizeInBytes) { return malloc(sizeInBytes); } @@ -578,27 +623,11 @@ class MySystem: public System { } virtual Status handleSegFault(SignalHandler* handler) { - if (handler) { - segFaultHandler = handler; + return registerHandler(handler, SegFaultIndex); + } -#ifdef ARCH_x86_32 - oldSegFaultHandler = SetUnhandledExceptionFilter(handleException); -#elif defined ARCH_x86_64 - AddVectoredExceptionHandler(1, handleException); - oldSegFaultHandler = 0; -#endif - return 0; - } else if (segFaultHandler) { - segFaultHandler = 0; -#ifdef ARCH_x86_32 - SetUnhandledExceptionFilter(oldSegFaultHandler); -#elif defined ARCH_x86_64 - //do nothing, handlers are never "unregistered" anyway -#endif - return 0; - } else { - return 1; - } + virtual Status handleDivideByZero(SignalHandler* handler) { + return registerHandler(handler, DivideByZeroIndex); } virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget, @@ -795,8 +824,8 @@ class MySystem: public System { } HANDLE mutex; - System::SignalHandler* segFaultHandler; - LPTOP_LEVEL_EXCEPTION_FILTER oldSegFaultHandler; + SignalHandler* handlers[HandlerCount]; + LPTOP_LEVEL_EXCEPTION_FILTER oldHandler; const char* crashDumpDirectory; }; @@ -867,7 +896,15 @@ dump(LPEXCEPTION_POINTERS e, const char* directory) LONG CALLBACK handleException(LPEXCEPTION_POINTERS e) { + System::SignalHandler* handler = 0; if (e->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + handler = system->handlers[SegFaultIndex]; + } else if (e->ExceptionRecord->ExceptionCode == EXCEPTION_INT_DIVIDE_BY_ZERO) + { + handler = system->handlers[DivideByZeroIndex]; + } + + if (handler) { #ifdef ARCH_x86_32 void* ip = reinterpret_cast(e->ContextRecord->Eip); void* base = reinterpret_cast(e->ContextRecord->Ebp); @@ -880,8 +917,8 @@ handleException(LPEXCEPTION_POINTERS e) void* thread = reinterpret_cast(e->ContextRecord->Rbx); #endif - bool jump = system->segFaultHandler->handleSignal - (&ip, &base, &stack, &thread); + bool jump = handler->handleSignal(&ip, &base, &stack, &thread); + #ifdef ARCH_x86_32 e->ContextRecord->Eip = reinterpret_cast(ip); e->ContextRecord->Ebp = reinterpret_cast(base); @@ -897,10 +934,10 @@ handleException(LPEXCEPTION_POINTERS e) if (jump) { return EXCEPTION_CONTINUE_EXECUTION; } + } - if (system->crashDumpDirectory) { - dump(e, system->crashDumpDirectory); - } + if (system->crashDumpDirectory) { + dump(e, system->crashDumpDirectory); } return EXCEPTION_CONTINUE_SEARCH; diff --git a/test/DivideByZero.java b/test/DivideByZero.java new file mode 100644 index 0000000000..80f308adcb --- /dev/null +++ b/test/DivideByZero.java @@ -0,0 +1,135 @@ +public class DivideByZero { + private static int divide(int n, int d) { + return n / d; + } + + private static int modulo(int n, int d) { + return n % d; + } + + private static long divide(long n, long d) { + return n / d; + } + + private static long modulo(long n, long d) { + return n % d; + } + + private static float divide(float n, float d) { + return n / d; + } + + private static float modulo(float n, float d) { + return n % d; + } + + private static double divide(double n, double d) { + return n / d; + } + + private static double modulo(double n, double d) { + return n % d; + } + + public static void main(String[] args) { + try { + int x = 1 / 0; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int x = 1 % 0; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int y = 2; + int x = y / 0; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int y = 2; + int x = y % 0; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int z = 0; + int y = 2; + int x = y / z; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + int z = 0; + int y = 2; + int x = y % z; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + long z = 0; + long y = 2; + long x = y / z; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + long z = 0; + long y = 2; + long x = y % z; + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + divide(5, 0); + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + modulo(6, 0); + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + divide(5L, 0L); + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + try { + modulo(6L, 0L); + throw new RuntimeException(); + } catch (ArithmeticException e) { + e.printStackTrace(); + } + + divide(5F, 0F); + modulo(6F, 0F); + + divide(5D, 0D); + modulo(6D, 0D); + } +} diff --git a/vm.pro b/vm.pro index edfd2e1679..e382722b5a 100644 --- a/vm.pro +++ b/vm.pro @@ -57,6 +57,7 @@ -keep public class java.lang.ClassCastException -keep public class java.lang.ClassNotFoundException -keep public class java.lang.NullPointerException +-keep public class java.lang.ArithmeticException -keep public class java.lang.InterruptedException -keep public class java.lang.StackOverflowError -keep public class java.lang.NoSuchFieldError