question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Support passing non-constant values to Exceptions in JIT

See original GitHub issue

Feature Request

In many cases it seems like it would be desirable to raise exceptions with strings that aren’t constants. My strongest use case is that I have an exception that happens in object mode, but because the message may be unclear and hard to determine, I want to append some additional information about the jit function is triggering this exception (for example function name and maybe argument values).

Here is an example where my exception message arises from using object mode.

import numba

@numba.njit
def f():
    with numba.objmode(res="unicode_type"):
        res = g()
    raise ValueError(f"Exception in f(): {res}")

def g():
    return "This is an Exception"

f()

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

2reactions
czgdp1807commented, May 7, 2022

So, I started working on this locally. Since, ValueError is a callable so while inferring constants in its arguments it reaches the following line,

https://github.com/numba/numba/blob/0f5953df2a2ee6eea1ac44b974bcd954aae91bc6/numba/core/consts.py#L96

Now, since we are passing a non-constant string so the above line fails and hence we get a ConstantInferenceError. The fix which I have thought of is this, if the callable is an exception then ignore the constaness of the message (i.e., change the above loop with the body having try-except block, catch ConstantInferenceError, if _exc is True then add a otherwise raise the caught exception). And in the numba/core/lowering.py add support for ir.Raise in a way similar to StaticRaise. I will post a diff on Monday even though if I fail implementing this approach (for learning purposes).

cc: @stuartarchibald @guilhermeleobas

0reactions
guilhermeleobascommented, May 31, 2022

I have a question regarding how exceptions are handled in Numba (cc @sklam, @stuartarchibald).

The exception triple (exc, val, tb) is serialized to the LLVM module as a constant string (ref). Is there any reason to why this step is important? Is there any feature (i.e. cache, object mode, AOT) that requires the exception triple to be serialized to the LLVM module?

By inspecting the LLVM module, the exception triple lifetime is:

  • Serialized to the LLVM module as a constant string.
  • At runtime, assuming an exception was raised, unpacks the excinfo pointer and calls _helperlib.c::numba_unpickle to reconstruct the triple as a pyobject.
  • Send the triple to _helperlib.c::numba_do_raise which reraises the exception.

The code below generates the following wrapper

@njit
def foo(a):
    raise ValueError('test message')
Wrapper generated
...

entry.endif.endif.endif:                          ; preds = %entry.endif.endif
  %.64 = call i32 @_ZN8__main__3fooB2v1B42c8tJTIcFHzwl2ILiXkcBV0KBSqPHEky4CKJAEwA_3dE12unicode_type(i8** undef, { i8*, i32, i8* }** nonnull %excinfo, i8* %.29, i64 %.31, i32 %.32, i32 %.33, i64 %.34, i8* %.48, i8* %.20) #2
  %.65 = load { i8*, i32, i8* }*, { i8*, i32, i8* }** %excinfo, align 8
  call void @NRT_decref(i8* %.48)
  switch i32 %.64, label %entry.endif.endif.endif.endif [
    i32 -2, label %entry.endif.endif.endif.if
    i32 0, label %entry.endif.endif.endif.if
  ]

entry.endif.endif.endif.if:                       ; preds = %entry.endif.endif.endif, %entry.endif.endif.endif
  call void @Py_IncRef(i8* nonnull @_Py_NoneStruct)
  ret i8* @_Py_NoneStruct

entry.endif.endif.endif.endif:                    ; preds = %entry.endif.endif.endif
  %.72 = icmp sgt i32 %.64, 0
  br i1 %.72, label %entry.endif.endif.endif.endif.if, label %entry.endif.endif.endif.endif.endif

entry.endif.endif.endif.endif.if:                 ; preds = %entry.endif.endif.endif.endif
  call void @PyErr_Clear()
  %.85 = load { i8*, i32, i8* }, { i8*, i32, i8* }* %.65, align 8
  %.86 = extractvalue { i8*, i32, i8* } %.85, 0
  %.88 = extractvalue { i8*, i32, i8* } %.85, 1
  %.90 = extractvalue { i8*, i32, i8* } %.85, 2
  %.91 = call i8* @numba_unpickle(i8* %.86, i32 %.88, i8* %.90)
  %.92.not = icmp eq i8* %.91, null
  br i1 %.92.not, label %entry.if, label %entry.endif.endif.endif.endif.if.if, !prof !7

entry.endif.endif.endif.endif.endif:              ; preds = %entry.endif.endif.endif.endif
  switch i32 %.64, label %entry.endif.endif.endif.endif.endif.endif.endif [
    i32 -3, label %entry.endif.endif.endif.endif.endif.if
    i32 -1, label %entry.if
  ]

entry.endif.endif.endif.endif.if.if:              ; preds = %entry.endif.endif.endif.endif.if
  call void @numba_do_raise(i8* nonnull %.91)
  br label %entry.if

Unless I am missing something, it seems to be possible to skip the serialization step and use the excinfo to store the triple directly. And with that, one could support non-constant messages in an exception.

Edit: I think I understand now why serialization is used.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Error using Numba to improve performance: non-constant value
Error: "TypingError: Failed in nopython mode pipeline (step: convert make_function into JIT functions) Cannot capture the non-constant value ...
Read more >
passing parameters to jax.jit 'ed functions #1922 - GitHub
I was thinking along the lines of a cpp code, where I can define a variable outside my function, and then pass a...
Read more >
Just-in-Time compilation - Numba documentation
Recompile all existing signatures. This can be useful for example if a global or closure variable was frozen by your function and its...
Read more >
Supported Python features - Numba
exceptions : try .. except , raise , else and finally (See details in this section) ... Once a function is assigned to...
Read more >
How to Throw Exceptions in Java - Rollbar
Throwing an exception is as simple as using the "throw" statement. You then specify the Exception object you wish to throw. Every Exception...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found