From de56d8c9508eeee417d85d413b7f3f7b3c9bd04f Mon Sep 17 00:00:00 2001 From: Eric Lunderberg Date: Wed, 25 Oct 2023 09:26:45 -0500 Subject: [PATCH] [Hotfix] Mark python-FFI handling with TVM_DLL (#15970) * [Hotfix] Mark python-FFI handling with TVM_DLL Bugfix for builds on Windows. * Updated declarations to match other usage in c_runtime_api.h --- include/tvm/runtime/c_runtime_api.h | 48 +++++++++++++++++++++++++++++ src/runtime/c_runtime_api.cc | 14 ++++----- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/include/tvm/runtime/c_runtime_api.h b/include/tvm/runtime/c_runtime_api.h index d678003ee8c3..b7474cbbae95 100644 --- a/include/tvm/runtime/c_runtime_api.h +++ b/include/tvm/runtime/c_runtime_api.h @@ -251,6 +251,18 @@ TVM_DLL void TVMAPISetLastError(const char* msg); */ TVM_DLL void TVMAPISetLastPythonError(void* py_object); +/*! \brief Return the previous python error, if any. + * + * Used to propagate the original Python exception to a python + * try/except, when there are C++ stack frames between the location thro + * + * \return The previous argument passed during the most recent call to + * TVMAPISetLastPythonError. If TVMAPISetLastPythonError has not + * been called, or if TVMDropLastPythonError has been called since + * the most recent to TVMAPISetLastPythonError, returns nullptr. + */ +TVM_DLL void* TVMGetLastPythonError(); + /*! * \brief return str message of the last error * all function in this file will return 0 when success @@ -261,6 +273,42 @@ TVM_DLL void TVMAPISetLastPythonError(void* py_object); * \return error info */ TVM_DLL const char* TVMGetLastError(void); + +/*! + * \brief Return the backtrace of the most recent error + * + * Returns the backtrace of the most recent error, if an error exists, + * and the error contains a backtrace. If no error exists or the + * error does not contain a backtrace, returns nullptr. + * + * \return The backtrace of the most recent error + */ +TVM_DLL const char* TVMGetLastBacktrace(); + +/*! + * \brief Remove the propagated python error, if any + * + * Removes the TVM-held reference to a thrown python exception object. + * Because these objects contain references to the stack frames from + * which the exception was thrown, maintaining a reference to an + * exception object prevents any local python variables from being + * garbage-collected. After retrieving the object using + * TVMGetLastPythonError, the Python FFI interface uses this method to + * clear the TVM-held reference to the exception, to allow garbage + * collection to continue. + */ +TVM_DLL void TVMDropLastPythonError(); + +/*! \brief Re-throw the most recent error. + * + * If an error was previously set using TVMAPISetLastError or + * TVMAPISetLastPythonError, re-throw the error. This is similar to + * `LOG(FATAL) << TVMGetLastError()`, but includes handling to + * propagate a python exception across C++ stack frames, or to append + * a stack trace to an error message. + */ +TVM_DLL void TVMThrowLastError(); + /*! * \brief Load module from file. * \param file_name The file name to load the module from. diff --git a/src/runtime/c_runtime_api.cc b/src/runtime/c_runtime_api.cc index 9f2ea8e2ffd7..0881eaf70427 100644 --- a/src/runtime/c_runtime_api.cc +++ b/src/runtime/c_runtime_api.cc @@ -418,7 +418,7 @@ const char* TVMGetLastError() { } } -extern "C" void* TVMGetLastPythonError() { +void* TVMGetLastPythonError() { auto& last_error = TVMAPIRuntimeStore::Get()->last_error; if (auto* wrapped = std::get_if(&last_error)) { return wrapped->obj.raw_pointer(); @@ -427,7 +427,7 @@ extern "C" void* TVMGetLastPythonError() { } } -extern "C" const char* TVMGetLastBacktrace() { +const char* TVMGetLastBacktrace() { const auto& last_error = TVMAPIRuntimeStore::Get()->last_error; if (const auto* wrapped = std::get_if(&last_error)) { return wrapped->cpp_backtrace.data(); @@ -438,7 +438,7 @@ extern "C" const char* TVMGetLastBacktrace() { } } -extern "C" void TVMDropLastPythonError() { +void TVMDropLastPythonError() { auto& last_error = TVMAPIRuntimeStore::Get()->last_error; if (std::get_if(&last_error)) { last_error = ""; @@ -458,12 +458,12 @@ int TVMAPIHandleException(const std::exception& e) { return -1; } -extern "C" void TVMAPISetLastPythonError(void* obj) { +void TVMAPISetLastPythonError(void* obj) { auto& last_error = TVMAPIRuntimeStore::Get()->last_error; last_error = WrappedPythonError(WrappedPythonObject(obj)); } -void ThrowLastError() { +void TVMThrowLastError() { auto& last_error = TVMAPIRuntimeStore::Get()->last_error; if (auto* wrapped = std::get_if(&last_error)) { WrappedPythonError wrapped_err; @@ -611,7 +611,7 @@ int TVMFuncCreateFromCFunc(TVMPackedCFunc func, void* resource_handle, TVMPacked int ret = func(const_cast(args.values), const_cast(args.type_codes), args.num_args, rv, resource_handle); if (ret != 0) { - ThrowLastError(); + TVMThrowLastError(); } }); TVMValue val; @@ -627,7 +627,7 @@ int TVMFuncCreateFromCFunc(TVMPackedCFunc func, void* resource_handle, TVMPacked int ret = func(const_cast(args.values), const_cast(args.type_codes), args.num_args, rv, rpack.get()); if (ret != 0) { - ThrowLastError(); + TVMThrowLastError(); } }); TVMValue val;