Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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
14 changes: 14 additions & 0 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,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 Expand Up @@ -400,6 +405,15 @@ struct AssertionError <: Exception
end
AssertionError() = AssertionError("")

abstract type FloatingPointException <: Exception end

struct DivideByZeroFloatingPointException <: FloatingPointException end
struct OverflowFloatingPointException <: FloatingPointException end
struct UnderflowFloatingPointException <: FloatingPointException end
struct InexactFloatingPointException <: FloatingPointException end
struct InvalidFloatingPointException <: FloatingPointException end


abstract type WrappedException <: Exception end

struct LoadError <: WrappedException
Expand Down
67 changes: 67 additions & 0 deletions base/rounding.jl
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,73 @@ for IEEE arithmetic, and `true` if they might be converted to zeros.
"""
get_zero_subnormals() = ccall(:jl_get_zero_subnormals,Int32,())!=0


function _get_exceptions()
excepts = ccall(:jl_get_fenv_except,Cint,())
if excepts < 0
error("Floating point exceptions not supported on this platform")
end
return excepts
end
function get_exceptions()
excepts = _get_exceptions()
return (;
invalid = excepts & JL_FE_INVALID != 0,
inexact = excepts & JL_FE_INEXACT != 0,
underflow = excepts & JL_FE_UNDERFLOW != 0,
overflow = excepts & JL_FE_OVERFLOW != 0,
dividebyzero = excepts & JL_FE_DIVBYZERO != 0,
)
end

function set_exceptions(;
invalid=nothing,
inexact=nothing,
overflow=nothing,
underflow=nothing,
dividebyzero=nothing
)
excepts = _get_exceptions()
if !isnothing(invalid)
if invalid
excepts |= JL_FE_INVALID
else
excepts &= ~JL_FE_INVALID
end
end
if !isnothing(inexact)
if inexact
excepts |= JL_FE_INEXACT
else
excepts &= ~JL_FE_INEXACT
end
end
if !isnothing(underflow)
if underflow
excepts |= JL_FE_UNDERFLOW
else
excepts &= ~JL_FE_UNDERFLOW
end
end
if !isnothing(overflow)
if overflow
excepts |= JL_FE_OVERFLOW
else
excepts &= ~JL_FE_OVERFLOW
end
end
if !isnothing(dividebyzero)
if dividebyzero
excepts |= JL_FE_DIVBYZERO
else
excepts &= ~JL_FE_DIVBYZERO
end
end
if ccall(:jl_set_fenv_except,Cint,(Cint,), excepts) < 0
error("Floating point exceptions not supported on this platform")
end
end

end #module
using .Rounding

Expand Down
5 changes: 5 additions & 0 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9376,6 +9376,11 @@ static void init_jit_functions(void)
global_jlvalue_to_llvm(new JuliaVariable{"jl_emptysvec", true, size2pjlvalue}, (jl_value_t**)&jl_emptysvec);
global_jlvalue_to_llvm(new JuliaVariable{"jl_emptytuple", true, size2pjlvalue}, &jl_emptytuple);
global_jlvalue_to_llvm(new JuliaVariable{"jl_diverror_exception", true, size2pjlvalue}, &jl_diverror_exception);
global_jlvalue_to_llvm(new JuliaVariable{"jl_divbyzero_fp_exception", true, size2pjlvalue}, &jl_divbyzero_fp_exception);
global_jlvalue_to_llvm(new JuliaVariable{"jl_overflow_fp_exception", true, size2pjlvalue}, &jl_overflow_fp_exception);
global_jlvalue_to_llvm(new JuliaVariable{"jl_underflow_fp_exception", true, size2pjlvalue}, &jl_underflow_fp_exception);
global_jlvalue_to_llvm(new JuliaVariable{"jl_inexact_fp_exception", true, size2pjlvalue}, &jl_inexact_fp_exception);
global_jlvalue_to_llvm(new JuliaVariable{"jl_invalid_fp_exception", true, size2pjlvalue}, &jl_invalid_fp_exception);
global_jlvalue_to_llvm(new JuliaVariable{"jl_undefref_exception", true, size2pjlvalue}, &jl_undefref_exception);
add_named_global(jlgetworld_global, &jl_world_counter);
add_named_global("__stack_chk_fail", &__stack_chk_fail);
Expand Down
5 changes: 5 additions & 0 deletions src/jl_exported_data.inc
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
XX(jl_datatype_type) \
XX(jl_densearray_type) \
XX(jl_diverror_exception) \
XX(jl_divbyzero_fp_exception) \
XX(jl_overflow_fp_exception) \
XX(jl_underflow_fp_exception) \
XX(jl_inexact_fp_exception) \
XX(jl_invalid_fp_exception) \
XX(jl_emptysvec) \
XX(jl_emptytuple) \
XX(jl_emptytuple_type) \
Expand Down
77 changes: 77 additions & 0 deletions src/jlapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
#include "tracy/TracyC.h"
#endif

#ifdef _OS_WINDOWS_
#include <float.h>
#endif

#ifdef __cplusplus
#include <cfenv>
extern "C" {
Expand Down Expand Up @@ -538,6 +542,79 @@ JL_DLLEXPORT int jl_set_fenv_rounding(int i)
return fesetround(i);
}


JL_DLLEXPORT int jl_get_fenv_except(void)
{
#if defined(__GLIBC__)
return fegetexcept();
#elif defined(_OS_WINDOWS_)
unsigned int flags = _controlfp(0, 0);
int excepts = 0;
if (flags & _EM_INEXACT)
excepts |= FE_INEXACT;
if (flags & _EM_UNDERFLOW)
excepts |= FE_UNDERFLOW;
if (flags & _EM_OVERFLOW)
excepts |= FE_OVERFLOW;
if (flags & _EM_ZERODIVIDE)
excepts |= FE_DIVBYZERO;
if (flags & _EM_INVALID)
excepts |= FE_INVALID;
return excepts;
#elif defined(_OS_DARWIN_)
fenv_t env;
fegetenv(&env);
#if defined(_CPU_AARCH64_)
return (env.__fpcr >> 8 & FE_ALL_EXCEPT);
#elif defined(_CPU_X86_64_)
return (~env.__mxcsr >> 7 & FE_ALL_EXCEPT);
#else
return -1;
#endif
#else
return -1;
#endif
}

JL_DLLEXPORT int jl_set_fenv_except(int excepts)
{
#if defined(__GLIBC__)
int prev_excepts = feenableexcept(excepts);
return prev_excepts >= 0;
#elif defined(_OS_WINDOWS_)
unsigned int flags = 0;
if (excepts & FE_INEXACT)
flags |= _EM_INEXACT;
if (excepts & FE_UNDERFLOW)
flags |= _EM_UNDERFLOW;
if (excepts & FE_OVERFLOW)
flags |= _EM_OVERFLOW;
if (excepts & FE_DIVBYZERO)
flags |= _EM_ZERODIVIDE;
if (excepts & FE_INVALID)
flags |= _EM_INVALID;
_controlfp(flags, _MCW_EM);
return 0;
#elif defined(_OS_DARWIN_)
// https://stackoverflow.com/questions/71821666/trapping-floating-point-exceptions-and-signal-handling-on-apple-silicon
fenv_t env;
fegetenv(&env);
#if defined(_CPU_AARCH64_)
env.__fpcr = (env.__fpcr & ~(FE_ALL_EXCEPT << 8)) | (excepts << 8);
#elif defined(_CPU_X86_64_)
env.__control = (env.__control | FE_ALL_EXCEPT) & ~excepts;
env.__mxcsr = (env.__mxcsr | FE_ALL_EXCEPT << 7) & ~(excepts << 7);
#else
return -1;
#endif
fesetenv(&env);
return 0;
#else
return -1;
#endif
}


static int exec_program(char *program)
{
JL_TRY {
Expand Down
5 changes: 5 additions & 0 deletions src/jltypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -3506,6 +3506,11 @@ void post_boot_hooks(void)
jl_errorexception_type = (jl_datatype_t*)core("ErrorException");
jl_stackovf_exception = jl_new_struct_uninit((jl_datatype_t*)core("StackOverflowError"));
jl_diverror_exception = jl_new_struct_uninit((jl_datatype_t*)core("DivideError"));
jl_divbyzero_fp_exception = jl_new_struct_uninit((jl_datatype_t*)core("DivideByZeroFloatingPointException"));
jl_overflow_fp_exception = jl_new_struct_uninit((jl_datatype_t*)core("OverflowFloatingPointException"));
jl_underflow_fp_exception = jl_new_struct_uninit((jl_datatype_t*)core("UnderflowFloatingPointException"));
jl_inexact_fp_exception = jl_new_struct_uninit((jl_datatype_t*)core("InexactFloatingPointException"));
jl_invalid_fp_exception = jl_new_struct_uninit((jl_datatype_t*)core("InvalidFloatingPointException"));
jl_undefref_exception = jl_new_struct_uninit((jl_datatype_t*)core("UndefRefError"));
jl_undefvarerror_type = (jl_datatype_t*)core("UndefVarError");
jl_atomicerror_type = (jl_datatype_t*)core("ConcurrencyViolationError");
Expand Down
5 changes: 5 additions & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -835,6 +835,11 @@ extern JL_DLLIMPORT jl_value_t *jl_stackovf_exception JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_value_t *jl_memory_exception JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_value_t *jl_readonlymemory_exception JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_value_t *jl_diverror_exception JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_value_t * jl_divbyzero_fp_exception JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_value_t * jl_overflow_fp_exception JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_value_t * jl_underflow_fp_exception JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_value_t * jl_inexact_fp_exception JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_value_t * jl_invalid_fp_exception JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_value_t *jl_undefref_exception JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_value_t *jl_interrupt_exception JL_GLOBALLY_ROOTED;
extern JL_DLLIMPORT jl_value_t *jl_precompilable_error JL_GLOBALLY_ROOTED;
Expand Down
50 changes: 50 additions & 0 deletions src/signals-mach.c
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,57 @@ 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/2ff845c2e033bd0ff64b5b6aa6063a1f8f65aa32/bsd/dev/arm/unix_signal.c#L436-L459
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;
}
#else
jl_throw_in_thread(ptls2, thread, jl_diverror_exception);
#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 @@ -1002,16 +1002,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 179
#define NUM_TAGS 184

// 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 @@ -234,6 +234,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
Loading