! * \brief Create an FFI function handle from a Python callable + optional DLPack exchange API. * * Allocates a TVMFFIPyCallbackClosure on the heap, IncRefs the callable, and * registers it with the FFI function-creation API using TVMFFIPyCallback as the * safe-call entry point and TVMFFIPyCallbackClosure::Deleter as the deleter. * * Returns the raw FFI return code (TLS FFI error set on fai
| 971 | * \return The return code from TVMFFIFunctionCreate (0 on success). |
| 972 | */ |
| 973 | TVM_FFI_INLINE int TVMFFIPyConvertPyCallback(PyObject* callable, |
| 974 | const DLPackExchangeAPI* dlpack_api, |
| 975 | TVMFFIObjectHandle* out_handle) noexcept { |
| 976 | // Use nothrow new: plain `new` can throw std::bad_alloc, which in this |
| 977 | // noexcept function would trigger std::terminate. On allocation failure, |
| 978 | // set PyErr and return -1 so the Cython caller's CHECK_CALL surfaces it. |
| 979 | auto* raw = new (std::nothrow) TVMFFIPyCallbackClosure{callable, dlpack_api}; |
| 980 | if (raw == nullptr) { |
| 981 | PyErr_NoMemory(); |
| 982 | return -1; |
| 983 | } |
| 984 | // The callable's +1 is owned by the closure; TVMFFIPyCallbackClosure::Deleter |
| 985 | // is responsible for Py_DecRef on destruction. By wiring the same Deleter as |
| 986 | // the unique_ptr deleter, the failure path below (unique_ptr unwind) runs |
| 987 | // the same cleanup as the success path (invoked by the FFI runtime). |
| 988 | Py_IncRef(callable); |
| 989 | std::unique_ptr<TVMFFIPyCallbackClosure, void (*)(void*)> closure( |
| 990 | raw, &TVMFFIPyCallbackClosure::Deleter); |
| 991 | int rc = TVMFFIFunctionCreate(closure.get(), &TVMFFIPyCallback, &TVMFFIPyCallbackClosure::Deleter, |
| 992 | out_handle); |
| 993 | // On success, transfer ownership to the FFI function; on failure, let |
| 994 | // unique_ptr unwind via Deleter (decrefs the callable, frees the closure). |
| 995 | if (rc == 0) closure.release(); |
| 996 | return rc; |
| 997 | } |
| 998 | |
| 999 | /*! |
| 1000 | * \brief Push a temporary FFI object to the call context that will be recycled after the call |
nothing calls this directly
no test coverage detected