Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for floating point exceptions #47930

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add signal hooks
  • Loading branch information
simonbyrne committed Dec 19, 2022
commit 29f880b3142c8a44504110623e2fd51411d6e052
5 changes: 5 additions & 0 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,11 @@ export
ErrorException, BoundsError, DivideError, DomainError, Exception,
InterruptException, InexactError, OutOfMemoryError, ReadOnlyMemoryError,
OverflowError, StackOverflowError, SegmentationFault, UndefRefError, UndefVarError,
DivideByZeroFloatingPointException,
OverflowFloatingPointException,
UnderflowFloatingPointException,
InexactFloatingPointException,
InvalidFloatingPointException,
TypeError, ArgumentError, MethodError, AssertionError, LoadError, InitError,
UndefKeywordError, ConcurrencyViolationError,
# AST representation
Expand Down
5 changes: 5 additions & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8402,6 +8402,11 @@ static void init_jit_functions(void)
global_jlvalue_to_llvm(new JuliaVariable{"jl_emptysvec", true, get_pjlvalue}, (jl_value_t**)&jl_emptysvec);
global_jlvalue_to_llvm(new JuliaVariable{"jl_emptytuple", true, get_pjlvalue}, &jl_emptytuple);
global_jlvalue_to_llvm(new JuliaVariable{"jl_diverror_exception", true, get_pjlvalue}, &jl_diverror_exception);
global_jlvalue_to_llvm(new JuliaVariable{"jl_divbyzero_fp_exception", true, get_pjlvalue}, &jl_divbyzero_fp_exception);
global_jlvalue_to_llvm(new JuliaVariable{"jl_overflow_fp_exception", true, get_pjlvalue}, &jl_overflow_fp_exception);
global_jlvalue_to_llvm(new JuliaVariable{"jl_underflow_fp_exception", true, get_pjlvalue}, &jl_underflow_fp_exception);
global_jlvalue_to_llvm(new JuliaVariable{"jl_inexact_fp_exception", true, get_pjlvalue}, &jl_inexact_fp_exception);
global_jlvalue_to_llvm(new JuliaVariable{"jl_invalid_fp_exception", true, get_pjlvalue}, &jl_invalid_fp_exception);
global_jlvalue_to_llvm(new JuliaVariable{"jl_undefref_exception", true, get_pjlvalue}, &jl_undefref_exception);
add_named_global(jlgetworld_global, &jl_world_counter);
add_named_global("__stack_chk_fail", &__stack_chk_fail);
Expand Down
48 changes: 48 additions & 0 deletions src/signals-mach.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,55 @@ kern_return_t catch_mach_exception_raise(
if (ptls2->gc_state == JL_GC_STATE_WAITING)
return KERN_FAILURE;
if (exception == EXC_ARITHMETIC) {
// https://github.com/apple/darwin-xnu/blob/a1babec6b135d1f35b2590a1990af3c5c5393479/osfmk/kern/ux_handler.c#L149
// uu_code = code[0]; uu_subcode = code[1]

#ifdef _CPU_X86_64_
// https://github.com/apple/darwin-xnu/blob/8f02f2a044b9bb1ad951987ef5bab20ec9486310/bsd/dev/i386/unix_signal.c#L535-L551
if (code[0] == EXC_I386_DIV) {
jl_throw_in_thread(ptls2, thread, jl_diverror_exception);
} else if (code[0] == EXC_I386_SSEEXTERR) {
// code[1] contains the contents of the MXCSR register
unsigned int flags = ~(code[1] >> 7) & code[1]; // extract unmasked flags

if (flags & (1 << 0)) // IE = invalid
jl_throw_in_thread(ptls2, thread, jl_invalid_fp_exception);
else if (flags & (1 << 1)) // DE = denormal
jl_throw_in_thread(ptls2, thread, jl_underflow_fp_exception);
else if (flags & (1 << 2)) // ZE = zero divide
jl_throw_in_thread(ptls2, thread, jl_divbyzero_fp_exception);
else if (flags & (1 << 3)) // OE = overflow
jl_throw_in_thread(ptls2, thread, jl_overflow_fp_exception);
else if (flags & (1 << 4)) // UE = underflow
jl_throw_in_thread(ptls2, thread, jl_underflow_fp_exception);
else if (flags & (1 << 5)) // PE = precision (inexact)
jl_throw_in_thread(ptls2, thread, jl_inexact_fp_exception);
}
#elif defined(_CPU_AARCH64_)
// https://github.com/apple/darwin-xnu/blob/8f02f2a044b9bb1ad951987ef5bab20ec9486310/bsd/dev/i386/unix_signal.c#L535-L551
switch (code[0]) {
case EXC_ARM_FP_UF:
jl_throw_in_thread(ptls2, thread, jl_underflow_fp_exception);
break;
case EXC_ARM_FP_OF:
jl_throw_in_thread(ptls2, thread, jl_overflow_fp_exception);
break;
case EXC_ARM_FP_IO:
jl_throw_in_thread(ptls2, thread, jl_invalid_fp_exception);
break;
case EXC_ARM_FP_DZ:
jl_throw_in_thread(ptls2, thread, jl_divbyzero_fp_exception);
break;
case EXC_ARM_FP_ID: // denormal
jl_throw_in_thread(ptls2, thread, jl_underflow_fp_exception);
break;
case EXC_ARM_FP_IX:
jl_throw_in_thread(ptls2, thread, jl_inexact_fp_exception);
break;
default:
break;
}
#endif
return KERN_SUCCESS;
}
assert(exception == EXC_BAD_ACCESS); // SIGSEGV or SIGBUS
Expand Down
13 changes: 11 additions & 2 deletions src/signals-unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -1016,16 +1016,25 @@ void restore_signals(void)

static void fpe_handler(int sig, siginfo_t *info, void *context)
{
(void)info;
if (jl_get_safe_restore()) { // restarting jl_ or profile
jl_call_in_ctx(NULL, &jl_sig_throw, sig, context);
return;
}
jl_task_t *ct = jl_get_current_task();
if (ct == NULL || ct->eh == NULL) // exception on foreign thread is fatal
sigdie_handler(sig, info, context);
else
else if (info->si_code == FPE_INTDIV)
jl_throw_in_ctx(ct, jl_diverror_exception, sig, context);
else if (info->si_code == FPE_FLTINV)
jl_throw_in_ctx(ct, jl_invalid_fp_exception, sig, context);
else if (info->si_code == FPE_FLTDIV)
jl_throw_in_ctx(ct, jl_divbyzero_fp_exception, sig, context);
else if (info->si_code == FPE_FLTOVF)
jl_throw_in_ctx(ct, jl_overflow_fp_exception, sig, context);
else if (info->si_code == FPE_FLTUND)
jl_throw_in_ctx(ct, jl_underflow_fp_exception, sig, context);
else if (info->si_code == FPE_FLTRES)
jl_throw_in_ctx(ct, jl_inexact_fp_exception, sig, context);
}

static void sigint_handler(int sig)
Expand Down
15 changes: 12 additions & 3 deletions src/signals-win.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,23 @@ void __cdecl crt_sig_handler(int sig, int num)
fpreset();
signal(SIGFPE, (void (__cdecl *)(int))crt_sig_handler);
switch(num) {
default:
jl_errorf("Unexpected FPE Error 0x%X", num);
break;
case _FPE_INVALID:
jl_throw(jl_invalid_fp_exception);
break;
case _FPE_OVERFLOW:
jl_throw(jl_overflow_fp_exception);
break;
case _FPE_UNDERFLOW:
default:
jl_errorf("Unexpected FPE Error 0x%X", num);
jl_throw(jl_underflow_fp_exception);
break;
case _FPE_ZERODIVIDE:
jl_throw(jl_diverror_exception);
jl_throw(jl_divbyzero_fp_exception);
break;
case _FPE_INEXACT:
jl_throw(jl_inexact_fp_exception);
break;
}
break;
Expand Down
7 changes: 6 additions & 1 deletion src/staticdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ extern "C" {
// TODO: put WeakRefs on the weak_refs list during deserialization
// TODO: handle finalizers

#define NUM_TAGS 158
#define NUM_TAGS 163

// An array of references that need to be restored from the sysimg
// This is a manually constructed dual of the gvars array, which would be produced by codegen for Julia code, for C.
Expand Down Expand Up @@ -219,6 +219,11 @@ jl_value_t **const*const get_tags(void) {
INSERT_TAG(jl_undefvarerror_type);
INSERT_TAG(jl_stackovf_exception);
INSERT_TAG(jl_diverror_exception);
INSERT_TAG(jl_divbyzero_fp_exception);
INSERT_TAG(jl_overflow_fp_exception);
INSERT_TAG(jl_underflow_fp_exception);
INSERT_TAG(jl_inexact_fp_exception);
INSERT_TAG(jl_invalid_fp_exception);
INSERT_TAG(jl_interrupt_exception);
INSERT_TAG(jl_boundserror_type);
INSERT_TAG(jl_memory_exception);
Expand Down