This is an automated email from the ASF dual-hosted git repository. tqchen pushed a commit to branch refactor-s3 in repository https://gitbox.apache.org/repos/asf/tvm.git
commit 4cf015723a346de52d3535695d488bd6d5e4d72c Author: tqchen <[email protected]> AuthorDate: Mon May 5 17:21:05 2025 -0400 [FFI] Update the API to use the ByteArray API --- ffi/CMakeLists.txt | 1 + ffi/include/tvm/ffi/c_api.h | 44 ++++++++------- ffi/include/tvm/ffi/dtype.h | 2 +- ffi/include/tvm/ffi/error.h | 49 ++++++++++++---- ffi/include/tvm/ffi/function.h | 37 +++++++----- ffi/include/tvm/ffi/object.h | 38 +++++++------ ffi/include/tvm/ffi/reflection/reflection.h | 10 ++-- ffi/include/tvm/ffi/string.h | 14 +++++ ffi/src/ffi/dtype.cc | 4 +- ffi/src/ffi/error.cc | 87 +++++++++++++++++++++++++++++ ffi/src/ffi/function.cc | 66 +++------------------- ffi/src/ffi/object.cc | 30 +++++----- ffi/src/ffi/traceback.cc | 14 +++-- ffi/src/ffi/traceback_win.cc | 7 ++- ffi/tests/cpp/test_any.cc | 12 ++-- ffi/tests/cpp/test_array.cc | 4 +- ffi/tests/cpp/test_dtype.cc | 2 +- ffi/tests/cpp/test_error.cc | 10 ++-- ffi/tests/cpp/test_function.cc | 32 +++++------ ffi/tests/cpp/test_map.cc | 4 +- ffi/tests/cpp/test_optional.cc | 2 +- ffi/tests/cpp/test_rvalue_ref.cc | 14 ++--- ffi/tests/cpp/test_tuple.cc | 20 +++---- ffi/tests/cpp/test_variant.cc | 16 +++--- python/tvm/ffi/cython/base.pxi | 56 +++++++++++++------ python/tvm/ffi/cython/dtype.pxi | 3 +- python/tvm/ffi/cython/error.pxi | 21 ++++--- python/tvm/ffi/cython/function.pxi | 8 ++- python/tvm/ffi/cython/object.pxi | 3 +- python/tvm/ffi/cython/string.pxi | 14 ----- src/node/reflection.cc | 3 +- src/runtime/c_runtime_api.cc | 7 ++- src/runtime/object_internal.h | 3 +- src/target/target.cc | 24 ++++---- 34 files changed, 398 insertions(+), 263 deletions(-) diff --git a/ffi/CMakeLists.txt b/ffi/CMakeLists.txt index ab9a3fabc3..abdc4fed05 100644 --- a/ffi/CMakeLists.txt +++ b/ffi/CMakeLists.txt @@ -61,6 +61,7 @@ add_library(tvm_ffi_objs OBJECT "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/traceback.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/traceback_win.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/object.cc" + "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/error.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/function.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/ndarray.cc" "${CMAKE_CURRENT_SOURCE_DIR}/src/ffi/dtype.cc" diff --git a/ffi/include/tvm/ffi/c_api.h b/ffi/include/tvm/ffi/c_api.h index f1f5f2f049..61738d1082 100644 --- a/ffi/include/tvm/ffi/c_api.h +++ b/ffi/include/tvm/ffi/c_api.h @@ -217,13 +217,13 @@ typedef struct { */ typedef struct { /*! \brief The kind of the error. */ - const char* kind; + TVMFFIByteArray kind; /*! \brief The message of the error. */ - const char* message; + TVMFFIByteArray message; /*! * \brief The traceback of the error. */ - const char* traceback; + TVMFFIByteArray traceback; } TVMFFIErrorCell; /*! @@ -288,7 +288,7 @@ typedef int (*TVMFFIFieldSetter)(void* field, const TVMFFIAny* value); */ typedef struct { /*! \brief The name of the field. */ - const char* name; + TVMFFIByteArray name; /*! * \brief Records the static type kind of the field. * @@ -326,7 +326,7 @@ typedef struct { */ typedef struct { /*! \brief The name of the field. */ - const char* name; + TVMFFIByteArray name; /*! * \brief The method wrapped as Function * \note The first argument to the method is always the self. @@ -346,7 +346,7 @@ typedef struct { /*! \brief number of parent types in the type hierachy. */ int32_t type_depth; /*! \brief the unique type key to identify the type. */ - const char* type_key; + TVMFFIByteArray type_key; /*! \brief Cached hash value of the type key, used for consistent structural hashing. */ uint64_t type_key_hash; /*! @@ -383,7 +383,7 @@ TVM_FFI_DLL int TVMFFIObjectFree(TVMFFIObjectHandle obj); * \param out_tindex the corresponding type index. * \return 0 when success, nonzero when failure happens */ -TVM_FFI_DLL int TVMFFITypeKeyToIndex(const char* type_key, int32_t* out_tindex); +TVM_FFI_DLL int TVMFFITypeKeyToIndex(const TVMFFIByteArray* type_key, int32_t* out_tindex); //----------------------------------------------------------------------- // Section: Function calling APIs and support API for func implementation @@ -432,7 +432,8 @@ TVM_FFI_DLL int TVMFFIFunctionCall(TVMFFIObjectHandle func, TVMFFIAny* args, int * \param override Whether allow override already registered function. * \return 0 when success, nonzero when failure happens */ -TVM_FFI_DLL int TVMFFIFunctionSetGlobal(const char* name, TVMFFIObjectHandle f, int override); +TVM_FFI_DLL int TVMFFIFunctionSetGlobal(const TVMFFIByteArray* name, TVMFFIObjectHandle f, + int override); /*! * \brief Get a global function. @@ -441,7 +442,7 @@ TVM_FFI_DLL int TVMFFIFunctionSetGlobal(const char* name, TVMFFIObjectHandle f, * \param out the result function pointer, NULL if it does not exist. * \return 0 when success, nonzero when failure happens */ -TVM_FFI_DLL int TVMFFIFunctionGetGlobal(const char* name, TVMFFIObjectHandle* out); +TVM_FFI_DLL int TVMFFIFunctionGetGlobal(const TVMFFIByteArray* name, TVMFFIObjectHandle* out); /*! * \brief Move the last error from the environment to result. @@ -474,18 +475,21 @@ TVM_FFI_DLL void TVMFFIErrorSetRaisedByCStr(const char* kind, const char* messag * \param kind The kind of the error. * \param message The error message. * \param traceback The traceback of the error. - * \param out The output Error object handle. - * \return 0 when success, nonzero when failure happens + * \return The created error object handle. + * \note This function is different from other functions as it is used in error handling loop. + * So we do not follow normal error handling patterns via returning error code. */ -TVM_FFI_DLL int TVMFFIErrorCreate(const char* kind, const char* message, const char* traceback, - TVMFFIObjectHandle* out); +TVM_FFI_DLL TVMFFIObjectHandle TVMFFIErrorCreate(const TVMFFIByteArray* kind, + const TVMFFIByteArray* message, + const TVMFFIByteArray* traceback); /*! * \brief Update the traceback of an Error object. * \param obj The error handle. * \param traceback The traceback to update. */ -TVM_FFI_DLL void TVMFFIErrorUpdateTraceback(TVMFFIObjectHandle obj, const char* traceback); +TVM_FFI_DLL void TVMFFIErrorUpdateTraceback(TVMFFIObjectHandle obj, + const TVMFFIByteArray* traceback); /*! * \brief Check if there are any signals raised in the surrounding env. @@ -500,7 +504,7 @@ TVM_FFI_DLL int TVMFFIEnvCheckSignals(); * \param symbol The symbol to register. * \return 0 when success, nonzero when failure happens */ -TVM_FFI_DLL int TVMFFIEnvRegisterCAPI(const char* name, void* symbol); +TVM_FFI_DLL int TVMFFIEnvRegisterCAPI(const TVMFFIByteArray* name, void* symbol); //------------------------------------------------------------ // Section: Type reflection support APIs @@ -568,7 +572,7 @@ TVM_FFI_DLL int TVMFFINDArrayToDLPackVersioned(TVMFFIObjectHandle from, * \param out The output DLDataType. * \return 0 when success, nonzero when failure happens */ -TVM_FFI_DLL int TVMFFIDataTypeFromString(const char* str, DLDataType* out); +TVM_FFI_DLL int TVMFFIDataTypeFromString(const TVMFFIByteArray* str, DLDataType* out); /*! * \brief Convert a DLDataType to a string. @@ -598,7 +602,8 @@ TVM_FFI_DLL int TVMFFIDataTypeToString(DLDataType dtype, TVMFFIObjectHandle* out * \note filename func and lino are only used as a backup info, most cases they are not needed. * The return value is set to const char* to be more compatible across dll boundaries. */ -TVM_FFI_DLL const char* TVMFFITraceback(const char* filename, int lineno, const char* func); +TVM_FFI_DLL const TVMFFIByteArray* TVMFFITraceback(const char* filename, int lineno, + const char* func); /*! * \brief Initialize the type info during runtime. @@ -619,8 +624,9 @@ TVM_FFI_DLL const char* TVMFFITraceback(const char* filename, int lineno, const * * \return 0 if success, -1 if error occured */ -TVM_FFI_DLL int32_t TVMFFIGetOrAllocTypeIndex(const char* type_key, int32_t static_type_index, - int32_t type_depth, int32_t num_child_slots, +TVM_FFI_DLL int32_t TVMFFIGetOrAllocTypeIndex(const TVMFFIByteArray* type_key, + int32_t static_type_index, int32_t type_depth, + int32_t num_child_slots, int32_t child_slots_can_overflow, int32_t parent_type_index); diff --git a/ffi/include/tvm/ffi/dtype.h b/ffi/include/tvm/ffi/dtype.h index 7dfb12d02a..99eb227ee1 100644 --- a/ffi/include/tvm/ffi/dtype.h +++ b/ffi/include/tvm/ffi/dtype.h @@ -115,7 +115,7 @@ inline const char* DLDataTypeCodeAsCStr(DLDataTypeCode type_code) { // NOLINT(* inline DLDataType StringToDLDataType(const String& str) { DLDataType out; - TVM_FFI_CHECK_SAFE_CALL(TVMFFIDataTypeFromString(str.c_str(), &out)); + TVM_FFI_CHECK_SAFE_CALL(TVMFFIDataTypeFromString(str.get(), &out)); return out; } diff --git a/ffi/include/tvm/ffi/error.h b/ffi/include/tvm/ffi/error.h index a07b66cd8d..4810754f17 100644 --- a/ffi/include/tvm/ffi/error.h +++ b/ffi/include/tvm/ffi/error.h @@ -33,6 +33,7 @@ #include <memory> #include <sstream> #include <string> +#include <string_view> #include <utility> /*! @@ -84,11 +85,9 @@ class ErrorObj : public Object, public TVMFFIErrorCell { * \brief Update the traceback of the error object. * \param traceback The traceback to update. */ - void UpdateTraceback(const char* traceback_str) { - this->traceback_data_ = traceback_str; - this->traceback = this->traceback_data_.c_str(); - this->what_data_ = (std::string("Traceback (most recent call last):\n") + this->traceback + - this->kind + ": " + this->message + '\n'); + void UpdateTraceback(const TVMFFIByteArray* traceback_str) { + this->traceback_data_ = std::string(traceback_str->data, traceback_str->size); + this->traceback = TVMFFIByteArray{this->traceback_data_.data(), this->traceback_data_.length()}; } static constexpr const int32_t _type_index = TypeIndex::kTVMFFIError; @@ -101,7 +100,6 @@ class ErrorObj : public Object, public TVMFFIErrorCell { std::string kind_data_; std::string message_data_; std::string traceback_data_; - std::string what_data_; }; /*! @@ -115,15 +113,39 @@ class Error : public ObjectRef, public std::exception { n->kind_data_ = std::move(kind); n->message_data_ = std::move(message); n->traceback_data_ = std::move(traceback); - n->kind = n->kind_data_.c_str(); - n->message = n->message_data_.c_str(); - n->traceback = n->traceback_data_.c_str(); - n->what_data_ = (std::string("Traceback (most recent call last):\n") + n->traceback + n->kind + - ": " + n->message + '\n'); + n->kind = TVMFFIByteArray{n->kind_data_.data(), n->kind_data_.length()}; + n->message = TVMFFIByteArray{n->message_data_.data(), n->message_data_.length()}; + n->traceback = TVMFFIByteArray{n->traceback_data_.data(), n->traceback_data_.length()}; data_ = std::move(n); } - const char* what() const noexcept(true) override { return get()->what_data_.c_str(); } + Error(std::string kind, std::string message, const TVMFFIByteArray* traceback) + : Error(kind, message, std::string(traceback->data, traceback->size)) {} + + std::string kind() const { + ErrorObj* obj = static_cast<ErrorObj*>(data_.get()); + return std::string(obj->kind.data, obj->kind.size); + } + + std::string message() const { + ErrorObj* obj = static_cast<ErrorObj*>(data_.get()); + return std::string(obj->message.data, obj->message.size); + } + + std::string traceback() const { + ErrorObj* obj = static_cast<ErrorObj*>(data_.get()); + return std::string(obj->traceback.data, obj->traceback.size); + } + + const char* what() const noexcept(true) override { + thread_local std::string what_data; + ErrorObj* obj = static_cast<ErrorObj*>(data_.get()); + what_data = (std::string("Traceback (most recent call last):\n") + + std::string(obj->traceback.data, obj->traceback.size) + + std::string(obj->kind.data, obj->kind.size) + std::string(": ") + + std::string(obj->message.data, obj->message.size) + '\n'); + return what_data.c_str(); + } TVM_FFI_DEFINE_NOTNULLABLE_OBJECT_REF_METHODS(Error, ObjectRef, ErrorObj); }; @@ -135,6 +157,9 @@ class ErrorBuilder { explicit ErrorBuilder(std::string kind, std::string traceback, bool log_before_throw) : kind_(kind), traceback_(traceback), log_before_throw_(log_before_throw) {} + explicit ErrorBuilder(std::string kind, const TVMFFIByteArray* traceback, bool log_before_throw) + : ErrorBuilder(kind, std::string(traceback->data, traceback->size), log_before_throw) {} + // MSVC disable warning in error builder as it is exepected #ifdef _MSC_VER #pragma disagnostic push diff --git a/ffi/include/tvm/ffi/function.h b/ffi/include/tvm/ffi/function.h index e4b67e4a76..d9f8986f5a 100644 --- a/ffi/include/tvm/ffi/function.h +++ b/ffi/include/tvm/ffi/function.h @@ -374,9 +374,10 @@ class Function : public ObjectRef { * \return The global function. * \note This function will return std::nullopt if the function is not found. */ - static std::optional<Function> GetGlobal(const char* name) { + static std::optional<Function> GetGlobal(std::string_view name) { TVMFFIObjectHandle handle; - TVM_FFI_CHECK_SAFE_CALL(TVMFFIFunctionGetGlobal(name, &handle)); + TVMFFIByteArray name_arr{name.data(), name.size()}; + TVM_FFI_CHECK_SAFE_CALL(TVMFFIFunctionGetGlobal(&name_arr, &handle)); if (handle != nullptr) { return Function( details::ObjectUnsafe::ObjectPtrFromOwned<Object>(static_cast<Object*>(handle))); @@ -386,18 +387,23 @@ class Function : public ObjectRef { } static std::optional<Function> GetGlobal(const std::string& name) { - return GetGlobal(name.c_str()); + return GetGlobal(std::string_view(name.data(), name.length())); } - static std::optional<Function> GetGlobal(const String& name) { return GetGlobal(name.c_str()); } + static std::optional<Function> GetGlobal(const String& name) { + return GetGlobal(std::string_view(name.data(), name.length())); + } + static std::optional<Function> GetGlobal(const char* name) { + return GetGlobal(std::string_view(name)); + } /*! * \brief Get global function by name and throw an error if it is not found. * \param name The name of the function * \return The global function * \note This function will throw an error if the function is not found. */ - static Function GetGlobalRequired(const char* name) { + static Function GetGlobalRequired(std::string_view name) { std::optional<Function> res = GetGlobal(name); if (!res.has_value()) { TVM_FFI_THROW(ValueError) << "Function " << name << " not found"; @@ -405,21 +411,25 @@ class Function : public ObjectRef { return res.value(); } - static Function GetGlobalRequired(const std::string& name) { - return GetGlobalRequired(name.c_str()); - } + static Function GetGlobalRequired(const std::string& name) { return GetGlobalRequired(name); } - static Function GetGlobalRequired(const String& name) { return GetGlobalRequired(name.c_str()); } + static Function GetGlobalRequired(const String& name) { + return GetGlobalRequired(std::string_view(name.data(), name.length())); + } + static Function GetGlobalRequired(const char* name) { + return GetGlobalRequired(std::string_view(name)); + } /*! * \brief Set global function by name * \param name The name of the function * \param func The function * \param override Whether to override when there is duplication. */ - static void SetGlobal(const char* name, Function func, bool override = false) { + static void SetGlobal(std::string_view name, Function func, bool override = false) { + TVMFFIByteArray name_arr{name.data(), name.size()}; TVM_FFI_CHECK_SAFE_CALL( - TVMFFIFunctionSetGlobal(name, details::ObjectUnsafe::GetHeader(func.get()), override)); + TVMFFIFunctionSetGlobal(&name_arr, details::ObjectUnsafe::GetHeader(func.get()), override)); } /*! * \brief List all global names @@ -876,9 +886,10 @@ class Function::Registry { /*! * \brief helper function to get type index from key */ -inline int32_t TypeKeyToIndex(const char* type_key) { +inline int32_t TypeKeyToIndex(std::string_view type_key) { int32_t type_index; - TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(type_key, &type_index)); + TVMFFIByteArray type_key_array = {type_key.data(), type_key.size()}; + TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(&type_key_array, &type_index)); return type_index; } diff --git a/ffi/include/tvm/ffi/object.h b/ffi/include/tvm/ffi/object.h index 248912e44f..e86689ebe2 100644 --- a/ffi/include/tvm/ffi/object.h +++ b/ffi/include/tvm/ffi/object.h @@ -64,7 +64,8 @@ struct StaticTypeKey { * \return the type key */ inline std::string TypeIndexToTypeKey(int32_t type_index) { - return TVMFFIGetTypeInfo(type_index)->type_key; + const TypeInfo* type_info = TVMFFIGetTypeInfo(type_index); + return std::string(type_info->type_key.data, type_info->type_key.size); } namespace details { @@ -155,7 +156,7 @@ class Object { std::string GetTypeKey() const { // the function checks that the info exists const TypeInfo* type_info = TVMFFIGetTypeInfo(header_.type_index); - return type_info->type_key; + return std::string(type_info->type_key.data, type_info->type_key.size); } /*! @@ -174,7 +175,7 @@ class Object { */ static std::string TypeIndex2Key(int32_t tindex) { const TypeInfo* type_info = TVMFFIGetTypeInfo(tindex); - return type_info->type_key; + return std::string(type_info->type_key.data, type_info->type_key.size); } bool unique() const { return use_count() == 1; } @@ -536,19 +537,20 @@ struct ObjectPtrEqual { }; // If dynamic type is enabled, we still need to register the runtime type of parent -#define TVM_FFI_REGISTER_STATIC_TYPE_INFO(TypeName, ParentType) \ - static constexpr int32_t _type_depth = ParentType::_type_depth + 1; \ - static int32_t _GetOrAllocRuntimeTypeIndex() { \ - static_assert(!ParentType::_type_final, "ParentType marked as final"); \ - static_assert(TypeName::_type_child_slots == 0 || ParentType::_type_child_slots == 0 || \ - TypeName::_type_child_slots < ParentType::_type_child_slots, \ - "Need to set _type_child_slots when parent specifies it."); \ - static int32_t tindex = TVMFFIGetOrAllocTypeIndex( \ - TypeName::_type_key, TypeName::_type_index, TypeName::_type_depth, \ - TypeName::_type_child_slots, TypeName::_type_child_slots_can_overflow, \ - ParentType::_GetOrAllocRuntimeTypeIndex()); \ - return tindex; \ - } \ +#define TVM_FFI_REGISTER_STATIC_TYPE_INFO(TypeName, ParentType) \ + static constexpr int32_t _type_depth = ParentType::_type_depth + 1; \ + static int32_t _GetOrAllocRuntimeTypeIndex() { \ + static_assert(!ParentType::_type_final, "ParentType marked as final"); \ + static_assert(TypeName::_type_child_slots == 0 || ParentType::_type_child_slots == 0 || \ + TypeName::_type_child_slots < ParentType::_type_child_slots, \ + "Need to set _type_child_slots when parent specifies it."); \ + TVMFFIByteArray type_key{TypeName::_type_key, \ + std::char_traits<char>::length(TypeName::_type_key)}; \ + static int32_t tindex = TVMFFIGetOrAllocTypeIndex( \ + &type_key, TypeName::_type_index, TypeName::_type_depth, TypeName::_type_child_slots, \ + TypeName::_type_child_slots_can_overflow, ParentType::_GetOrAllocRuntimeTypeIndex()); \ + return tindex; \ + } \ static inline int32_t _register_type_index = _GetOrAllocRuntimeTypeIndex() /*! @@ -572,8 +574,10 @@ struct ObjectPtrEqual { static_assert(TypeName::_type_child_slots == 0 || ParentType::_type_child_slots == 0 || \ TypeName::_type_child_slots < ParentType::_type_child_slots, \ "Need to set _type_child_slots when parent specifies it."); \ + TVMFFIByteArray type_key{TypeName::_type_key, \ + std::char_traits<char>::length(TypeName::_type_key)}; \ static int32_t tindex = TVMFFIGetOrAllocTypeIndex( \ - TypeName::_type_key, -1, TypeName::_type_depth, TypeName::_type_child_slots, \ + &type_key, -1, TypeName::_type_depth, TypeName::_type_child_slots, \ TypeName::_type_child_slots_can_overflow, ParentType::_GetOrAllocRuntimeTypeIndex()); \ return tindex; \ } \ diff --git a/ffi/include/tvm/ffi/reflection/reflection.h b/ffi/include/tvm/ffi/reflection/reflection.h index 8ce2d22ddd..034ff840d4 100644 --- a/ffi/include/tvm/ffi/reflection/reflection.h +++ b/ffi/include/tvm/ffi/reflection/reflection.h @@ -70,7 +70,7 @@ class ReflectionDef { template <typename Class, typename T> void RegisterField(const char* name, T Class::*field_ptr, bool readonly) { TVMFFIFieldInfo info; - info.name = name; + info.name = TVMFFIByteArray{name, std::char_traits<char>::length(name)}; info.field_static_type_index = TypeToFieldStaticTypeIndex<T>::value; // store byte offset and setter, getter // so the same setter can be reused for all the same type @@ -101,12 +101,14 @@ class ReflectionDef { /*! * \brief helper function to get reflection field info by type key and field name */ -inline const TVMFFIFieldInfo* GetReflectionFieldInfo(const char* type_key, const char* field_name) { +inline const TVMFFIFieldInfo* GetReflectionFieldInfo(std::string_view type_key, + const char* field_name) { int32_t type_index; - TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(type_key, &type_index)); + TVMFFIByteArray type_key_array = {type_key.data(), type_key.size()}; + TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(&type_key_array, &type_index)); const TypeInfo* info = TVMFFIGetTypeInfo(type_index); for (int32_t i = 0; i < info->num_fields; ++i) { - if (std::strcmp(info->fields[i].name, field_name) == 0) { + if (std::strncmp(info->fields[i].name.data, field_name, info->fields[i].name.size) == 0) { return &(info->fields[i]); } } diff --git a/ffi/include/tvm/ffi/string.h b/ffi/include/tvm/ffi/string.h index 2fbbb551a1..1c22f10892 100644 --- a/ffi/include/tvm/ffi/string.h +++ b/ffi/include/tvm/ffi/string.h @@ -74,6 +74,7 @@ class StringObj : public BytesObjBase { }; namespace details { + // String moved from std::string // without having to trigger a copy template <typename Base> @@ -233,6 +234,14 @@ class String : public ObjectRef { String(const char* other) // NOLINT(*) : ObjectRef(details::MakeInplaceBytes<StringObj>(other, std::strlen(other))) {} + /*! + * \brief constructor from raw string + * + * \param other a char array. + */ + String(const char* other, size_t size) // NOLINT(*) + : ObjectRef(details::MakeInplaceBytes<StringObj>(other, size)) {} + /*! * \brief Construct a new string object * \param other The std::string object to be copied @@ -383,6 +392,11 @@ class String : public ObjectRef { friend String operator+(const char* lhs, const String& rhs); }; +/*! \brief Convert TVMFFIByteArray to std::string_view */ +TVM_FFI_INLINE std::string_view ToStringView(TVMFFIByteArray str) { + return std::string_view(str.data, str.size); +} + // const char*, requirement: not nullable, do not retain ownership template <int N> struct TypeTraits<char[N]> : public TypeTraitsBase { diff --git a/ffi/src/ffi/dtype.cc b/ffi/src/ffi/dtype.cc index cad38b3240..7661ab4b97 100644 --- a/ffi/src/ffi/dtype.cc +++ b/ffi/src/ffi/dtype.cc @@ -314,9 +314,9 @@ inline DLDataType StringViewToDLDataType_(std::string_view str) { } // namespace ffi } // namespace tvm -int TVMFFIDataTypeFromString(const char* str, DLDataType* out) { +int TVMFFIDataTypeFromString(const TVMFFIByteArray* str, DLDataType* out) { TVM_FFI_SAFE_CALL_BEGIN(); - *out = tvm::ffi::StringViewToDLDataType_(std::string_view(str)); + *out = tvm::ffi::StringViewToDLDataType_(std::string_view(str->data, str->size)); TVM_FFI_SAFE_CALL_END(); } diff --git a/ffi/src/ffi/error.cc b/ffi/src/ffi/error.cc new file mode 100644 index 0000000000..4dcfb67714 --- /dev/null +++ b/ffi/src/ffi/error.cc @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +/* + * \file src/ffi/error.cc + * \brief Error handling implementation + */ +#include <tvm/ffi/c_api.h> +#include <tvm/ffi/error.h> + +namespace tvm { +namespace ffi { + +class SafeCallContext { + public: + void SetRaised(TVMFFIObjectHandle error) { + last_error_ = + details::ObjectUnsafe::ObjectPtrFromUnowned<ErrorObj>(static_cast<TVMFFIObject*>(error)); + } + + void SetRaisedByCstr(const char* kind, const char* message, const TVMFFIByteArray* traceback) { + Error error(kind, message, traceback); + last_error_ = details::ObjectUnsafe::ObjectPtrFromObjectRef<ErrorObj>(std::move(error)); + } + + void MoveFromRaised(TVMFFIObjectHandle* result) { + result[0] = details::ObjectUnsafe::MoveObjectPtrToTVMFFIObjectPtr(std::move(last_error_)); + } + + static SafeCallContext* ThreadLocal() { + static thread_local SafeCallContext ctx; + return &ctx; + } + + private: + ObjectPtr<ErrorObj> last_error_; +}; + +} // namespace ffi +} // namespace tvm + +void TVMFFIErrorSetRaisedByCStr(const char* kind, const char* message) { + // NOTE: run traceback here to simplify the depth of tracekback + tvm::ffi::SafeCallContext::ThreadLocal()->SetRaisedByCstr(kind, message, TVM_FFI_TRACEBACK_HERE); +} + +void TVMFFIErrorSetRaised(TVMFFIObjectHandle error) { + tvm::ffi::SafeCallContext::ThreadLocal()->SetRaised(error); +} + +void TVMFFIErrorMoveFromRaised(TVMFFIObjectHandle* result) { + tvm::ffi::SafeCallContext::ThreadLocal()->MoveFromRaised(result); +} + +void TVMFFIErrorUpdateTraceback(TVMFFIObjectHandle obj, const TVMFFIByteArray* traceback) { + TVM_FFI_LOG_EXCEPTION_CALL_BEGIN(); + static_cast<tvm::ffi::ErrorObj*>(reinterpret_cast<tvm::ffi::Object*>(obj)) + ->UpdateTraceback(traceback); + TVM_FFI_LOG_EXCEPTION_CALL_END(TVMFFIErrorUpdateTraceback); +} + +TVMFFIObjectHandle TVMFFIErrorCreate(const TVMFFIByteArray* kind, const TVMFFIByteArray* message, + const TVMFFIByteArray* traceback) { + TVM_FFI_LOG_EXCEPTION_CALL_BEGIN(); + tvm::ffi::Error error(std::string(kind->data, kind->size), + std::string(message->data, message->size), + std::string(traceback->data, traceback->size)); + TVMFFIObjectHandle out = + tvm::ffi::details::ObjectUnsafe::MoveObjectRefToTVMFFIObjectPtr(std::move(error)); + return out; + TVM_FFI_LOG_EXCEPTION_CALL_END(TVMFFIErrorCreate); +} diff --git a/ffi/src/ffi/function.cc b/ffi/src/ffi/function.cc index f442ceb248..ed10ea59c9 100644 --- a/ffi/src/ffi/function.cc +++ b/ffi/src/ffi/function.cc @@ -33,31 +33,6 @@ namespace tvm { namespace ffi { -class SafeCallContext { - public: - void SetRaised(TVMFFIObjectHandle error) { - last_error_ = - details::ObjectUnsafe::ObjectPtrFromUnowned<ErrorObj>(static_cast<TVMFFIObject*>(error)); - } - - void SetRaisedByCstr(const char* kind, const char* message, const char* traceback) { - Error error(kind, message, traceback); - last_error_ = details::ObjectUnsafe::ObjectPtrFromObjectRef<ErrorObj>(std::move(error)); - } - - void MoveFromRaised(TVMFFIObjectHandle* result) { - result[0] = details::ObjectUnsafe::MoveObjectPtrToTVMFFIObjectPtr(std::move(last_error_)); - } - - static SafeCallContext* ThreadLocal() { - static thread_local SafeCallContext ctx; - return &ctx; - } - - private: - ObjectPtr<ErrorObj> last_error_; -}; - /*! * \brief Global function table. * @@ -241,18 +216,20 @@ int TVMFFIAnyViewToOwnedAny(const TVMFFIAny* any_view, TVMFFIAny* out) { TVM_FFI_SAFE_CALL_END(); } -int TVMFFIFunctionSetGlobal(const char* name, TVMFFIObjectHandle f, int override) { +int TVMFFIFunctionSetGlobal(const TVMFFIByteArray* name, TVMFFIObjectHandle f, int override) { using namespace tvm::ffi; TVM_FFI_SAFE_CALL_BEGIN(); - GlobalFunctionTable::Global()->Update(name, GetRef<Function>(static_cast<FunctionObj*>(f)), + String name_str(name->data, name->size); + GlobalFunctionTable::Global()->Update(name_str, GetRef<Function>(static_cast<FunctionObj*>(f)), override != 0); TVM_FFI_SAFE_CALL_END(); } -int TVMFFIFunctionGetGlobal(const char* name, TVMFFIObjectHandle* out) { +int TVMFFIFunctionGetGlobal(const TVMFFIByteArray* name, TVMFFIObjectHandle* out) { using namespace tvm::ffi; TVM_FFI_SAFE_CALL_BEGIN(); - const Function* fp = GlobalFunctionTable::Global()->Get(name); + String name_str(name->data, name->size); + const Function* fp = GlobalFunctionTable::Global()->Get(name_str); if (fp != nullptr) { tvm::ffi::Function func(*fp); *out = tvm::ffi::details::ObjectUnsafe::MoveObjectRefToTVMFFIObjectPtr(std::move(func)); @@ -269,32 +246,6 @@ int TVMFFIFunctionCall(TVMFFIObjectHandle func, TVMFFIAny* args, int32_t num_arg return reinterpret_cast<FunctionObj*>(func)->safe_call(func, args, num_args, result); } -void TVMFFIErrorSetRaisedByCStr(const char* kind, const char* message) { - // NOTE: run traceback here to simplify the depth of tracekback - tvm::ffi::SafeCallContext::ThreadLocal()->SetRaisedByCstr(kind, message, TVM_FFI_TRACEBACK_HERE); -} - -void TVMFFIErrorSetRaised(TVMFFIObjectHandle error) { - tvm::ffi::SafeCallContext::ThreadLocal()->SetRaised(error); -} - -void TVMFFIErrorMoveFromRaised(TVMFFIObjectHandle* result) { - tvm::ffi::SafeCallContext::ThreadLocal()->MoveFromRaised(result); -} - -void TVMFFIErrorUpdateTraceback(TVMFFIObjectHandle obj, const char* traceback) { - static_cast<tvm::ffi::ErrorObj*>(reinterpret_cast<tvm::ffi::Object*>(obj)) - ->UpdateTraceback(traceback); -} - -int TVMFFIErrorCreate(const char* kind, const char* message, const char* traceback, - TVMFFIObjectHandle* out) { - TVM_FFI_SAFE_CALL_BEGIN(); - tvm::ffi::Error error(kind, message, traceback); - *out = tvm::ffi::details::ObjectUnsafe::MoveObjectRefToTVMFFIObjectPtr(std::move(error)); - TVM_FFI_SAFE_CALL_END(); -} - int TVMFFIEnvCheckSignals() { return tvm::ffi::EnvCAPIRegistry::Global()->EnvCheckSignals(); } /*! @@ -303,9 +254,10 @@ int TVMFFIEnvCheckSignals() { return tvm::ffi::EnvCAPIRegistry::Global()->EnvChe * \param symbol The symbol to register. * \return 0 when success, nonzero when failure happens */ -int TVMFFIEnvRegisterCAPI(const char* name, void* symbol) { +int TVMFFIEnvRegisterCAPI(const TVMFFIByteArray* name, void* symbol) { TVM_FFI_SAFE_CALL_BEGIN(); - tvm::ffi::EnvCAPIRegistry::Global()->Register(name, symbol); + std::string s_name(name->data, name->size); + tvm::ffi::EnvCAPIRegistry::Global()->Register(s_name, symbol); TVM_FFI_SAFE_CALL_END(); } diff --git a/ffi/src/ffi/object.cc b/ffi/src/ffi/object.cc index de3fd04523..63ec68790e 100644 --- a/ffi/src/ffi/object.cc +++ b/ffi/src/ffi/object.cc @@ -86,7 +86,7 @@ class TypeTable { // after this line this->type_index = type_index; this->type_depth = type_depth; - this->type_key = this->type_key_data.c_str(); + this->type_key = TVMFFIByteArray{this->type_key_data.data(), this->type_key_data.length()}; this->type_key_hash = std::hash<std::string>()(this->type_key_data); this->type_acenstors = type_acenstors_data.data(); // initialize the reflection information @@ -121,7 +121,7 @@ class TypeTable { TVM_FFI_ICHECK_LT(static_type_index, type_table_.size()); TVM_FFI_ICHECK(type_table_[static_type_index] == nullptr) << "Conflicting static index " << static_type_index << " between " - << type_table_[static_type_index]->type_key << " and " << type_key; + << ToStringView(type_table_[static_type_index]->type_key) << " and " << type_key; return static_type_index; } TVM_FFI_ICHECK_NOTNULL(parent); @@ -135,7 +135,7 @@ class TypeTable { } // Step 2: allocate from overflow TVM_FFI_ICHECK(parent->child_slots_can_overflow) - << "Reach maximum number of sub-classes for " << parent->type_key; + << "Reach maximum number of sub-classes for " << ToStringView(parent->type_key); // allocate new entries. int32_t allocated_tindex = type_counter_; type_counter_ += num_slots; @@ -166,9 +166,10 @@ class TypeTable { return allocated_tindex; } - int32_t TypeKeyToIndex(const std::string& type_key) { - auto it = type_key2index_.find(type_key); - TVM_FFI_ICHECK(it != type_key2index_.end()) << "Cannot find type `" << type_key << "`"; + int32_t TypeKeyToIndex(const TVMFFIByteArray* type_key) { + std::string type_key_str(type_key->data, type_key->size); + auto it = type_key2index_.find(type_key_str); + TVM_FFI_ICHECK(it != type_key2index_.end()) << "Cannot find type `" << type_key_str << "`"; return it->second; } @@ -211,10 +212,10 @@ class TypeTable { for (const auto& ptr : type_table_) { if (ptr != nullptr && num_children[ptr->type_index] >= min_children_count) { - std::cerr << '[' << ptr->type_index << "]\t" << ptr->type_key; + std::cerr << '[' << ptr->type_index << "]\t" << ToStringView(ptr->type_key); if (ptr->type_depth != 0) { int32_t parent_index = ptr->type_acenstors[ptr->type_depth - 1]; - std::cerr << "\tparent=" << type_table_[parent_index]->type_key; + std::cerr << "\tparent=" << ToStringView(type_table_[parent_index]->type_key); } else { std::cerr << "\tparent=root"; } @@ -260,9 +261,9 @@ class TypeTable { this->GetOrAllocTypeIndex(type_key, static_type_index, 0, 0, false, -1); } - const char* CopyString(const char* c_str) { - std::unique_ptr<std::string> val = std::make_unique<std::string>(c_str); - const char* c_val = val->c_str(); + TVMFFIByteArray CopyString(TVMFFIByteArray str) { + std::unique_ptr<std::string> val = std::make_unique<std::string>(str.data, str.size); + TVMFFIByteArray c_val{val->data(), val->length()}; string_pool_.emplace_back(std::move(val)); return c_val; } @@ -281,7 +282,7 @@ int TVMFFIObjectFree(TVMFFIObjectHandle handle) { TVM_FFI_SAFE_CALL_END(); } -int TVMFFITypeKeyToIndex(const char* type_key, int32_t* out_tindex) { +int TVMFFITypeKeyToIndex(const TVMFFIByteArray* type_key, int32_t* out_tindex) { TVM_FFI_SAFE_CALL_BEGIN(); out_tindex[0] = tvm::ffi::TypeTable::Global()->TypeKeyToIndex(type_key); TVM_FFI_SAFE_CALL_END(); @@ -293,12 +294,13 @@ int TVMFFIRegisterTypeField(int32_t type_index, const TVMFFIFieldInfo* info) { TVM_FFI_SAFE_CALL_END(); } -int32_t TVMFFIGetOrAllocTypeIndex(const char* type_key, int32_t static_type_index, +int32_t TVMFFIGetOrAllocTypeIndex(const TVMFFIByteArray* type_key, int32_t static_type_index, int32_t type_depth, int32_t num_child_slots, int32_t child_slots_can_overflow, int32_t parent_type_index) { TVM_FFI_LOG_EXCEPTION_CALL_BEGIN(); + std::string s_type_key = std::string(type_key->data, type_key->size); return tvm::ffi::TypeTable::Global()->GetOrAllocTypeIndex( - type_key, static_type_index, type_depth, num_child_slots, child_slots_can_overflow, + s_type_key, static_type_index, type_depth, num_child_slots, child_slots_can_overflow, parent_type_index); TVM_FFI_LOG_EXCEPTION_CALL_END(TVMFFIGetOrAllocTypeIndex); } diff --git a/ffi/src/ffi/traceback.cc b/ffi/src/ffi/traceback.cc index 7cebc37774..4c7fb25427 100644 --- a/ffi/src/ffi/traceback.cc +++ b/ffi/src/ffi/traceback.cc @@ -149,20 +149,26 @@ __attribute__((constructor)) void install_signal_handler(void) { } // namespace ffi } // namespace tvm -const char* TVMFFITraceback(const char*, int, const char*) { +const TVMFFIByteArray* TVMFFITraceback(const char*, int, const char*) { static thread_local std::string traceback_str; + static thread_local TVMFFIByteArray traceback_array; traceback_str = ::tvm::ffi::Traceback(); - return traceback_str.c_str(); + traceback_array.data = traceback_str.data(); + traceback_array.size = traceback_str.size(); + return &traceback_array; } #else // fallback implementation simply print out the last trace -const char* TVMFFITraceback(const char* filename, int lineno, const char* func) { +const TVMFFIByteArray* TVMFFITraceback(const char* filename, int lineno, const char* func) { static thread_local std::string traceback_str; + static thread_local TVMFFIByteArray traceback_array; std::ostringstream traceback_stream; // python style backtrace traceback_stream << " File \"" << filename << "\", line " << lineno << ", in " << func << '\n'; traceback_str = traceback_stream.str(); - return traceback_str.c_str(); + traceback_array.data = traceback_str.data(); + traceback_array.size = traceback_str.size(); + return &traceback_array; } #endif // TVM_FFI_USE_LIBBACKTRACE #endif // _MSC_VER diff --git a/ffi/src/ffi/traceback_win.cc b/ffi/src/ffi/traceback_win.cc index d49f9e00af..0bdb536ae5 100644 --- a/ffi/src/ffi/traceback_win.cc +++ b/ffi/src/ffi/traceback_win.cc @@ -122,9 +122,12 @@ std::string Traceback() { } // namespace ffi } // namespace tvm -const char* TVMFFITraceback(const char*, int, const char*) { +const TVMFFIByteArray* TVMFFITraceback() { static thread_local std::string traceback_str; + static thread_local TVMFFIByteArray traceback_array; traceback_str = ::tvm::ffi::Traceback(); - return traceback_str.c_str(); + traceback_array.data = traceback_str.data(); + traceback_array.size = traceback_str.size(); + return &traceback_array; } #endif // _MSC_VER diff --git a/ffi/tests/cpp/test_any.cc b/ffi/tests/cpp/test_any.cc index 496ae9469d..816ae28e0e 100644 --- a/ffi/tests/cpp/test_any.cc +++ b/ffi/tests/cpp/test_any.cc @@ -39,7 +39,7 @@ TEST(Any, Int) { try { [[maybe_unused]] auto v0 = view0.cast<int>(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); + EXPECT_EQ(error.kind(), "TypeError"); std::string what = error.what(); EXPECT_NE(what.find("Cannot convert from type `None` to `int`"), std::string::npos); throw; @@ -70,7 +70,7 @@ TEST(Any, bool) { try { [[maybe_unused]] auto v0 = view0.cast<bool>(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); + EXPECT_EQ(error.kind(), "TypeError"); std::string what = error.what(); EXPECT_NE(what.find("Cannot convert from type `None` to `bool`"), std::string::npos); throw; @@ -122,7 +122,7 @@ TEST(Any, Float) { try { [[maybe_unused]] auto v0 = view0.cast<double>(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); + EXPECT_EQ(error.kind(), "TypeError"); std::string what = error.what(); EXPECT_NE(what.find("Cannot convert from type `None` to `float`"), std::string::npos); throw; @@ -156,7 +156,7 @@ TEST(Any, Device) { try { [[maybe_unused]] auto v0 = view0.cast<DLDevice>(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); + EXPECT_EQ(error.kind(), "TypeError"); std::string what = error.what(); EXPECT_NE(what.find("Cannot convert from type `None` to `Device`"), std::string::npos); throw; @@ -189,7 +189,7 @@ TEST(Any, DLTensor) { try { [[maybe_unused]] auto v0 = view0.cast<DLTensor*>(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); + EXPECT_EQ(error.kind(), "TypeError"); std::string what = error.what(); EXPECT_NE(what.find("Cannot convert from type `None` to `DLTensor*`"), std::string::npos); throw; @@ -253,7 +253,7 @@ TEST(Any, Object) { try { [[maybe_unused]] auto v0 = view1.cast<TFloat>(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); + EXPECT_EQ(error.kind(), "TypeError"); std::string what = error.what(); std::cout << what; EXPECT_NE(what.find("Cannot convert from type `test.Int` to `test.Float`"), diff --git a/ffi/tests/cpp/test_array.cc b/ffi/tests/cpp/test_array.cc index b268cf1039..bb0b062c32 100644 --- a/ffi/tests/cpp/test_array.cc +++ b/ffi/tests/cpp/test_array.cc @@ -239,7 +239,7 @@ TEST(Array, AnyConvertCheck) { try { [[maybe_unused]] auto arr2 = any1.cast<Array<int>>(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); + EXPECT_EQ(error.kind(), "TypeError"); std::string what = error.what(); EXPECT_NE(what.find("Cannot convert from type `Array[index 0: float]` to `Array<int>`"), std::string::npos); @@ -258,7 +258,7 @@ TEST(Array, AnyConvertCheck) { try { [[maybe_unused]] auto arr2 = any1.cast<Array<Array<int>>>(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); + EXPECT_EQ(error.kind(), "TypeError"); std::string what = error.what(); EXPECT_NE(what.find("`Array[index 1: Array[index 0: test.Int]]` to `Array<Array<int>>`"), std::string::npos); diff --git a/ffi/tests/cpp/test_dtype.cc b/ffi/tests/cpp/test_dtype.cc index 5dce997a9a..e31df8761d 100644 --- a/ffi/tests/cpp/test_dtype.cc +++ b/ffi/tests/cpp/test_dtype.cc @@ -86,7 +86,7 @@ TEST(DataType, AnyConversion) { try { [[maybe_unused]] auto v0 = view0.cast<DLDataType>(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); + EXPECT_EQ(error.kind(), "TypeError"); std::string what = error.what(); EXPECT_NE(what.find("Cannot convert from type `None` to `DataType`"), std::string::npos); throw; diff --git a/ffi/tests/cpp/test_error.cc b/ffi/tests/cpp/test_error.cc index e6e17e0a91..9938603a47 100644 --- a/ffi/tests/cpp/test_error.cc +++ b/ffi/tests/cpp/test_error.cc @@ -33,8 +33,8 @@ TEST(Error, Traceback) { try { ThrowRuntimeError(); } catch (const Error& error) { - EXPECT_STREQ(error->message, "test0"); - EXPECT_STREQ(error->kind, "RuntimeError"); + EXPECT_EQ(error.message(), "test0"); + EXPECT_EQ(error.kind(), "RuntimeError"); std::string what = error.what(); EXPECT_NE(what.find("line"), std::string::npos); EXPECT_NE(what.find("ThrowRuntimeError"), std::string::npos); @@ -51,7 +51,7 @@ TEST(CheckError, Traceback) { try { TVM_FFI_ICHECK_GT(2, 3); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "InternalError"); + EXPECT_EQ(error.kind(), "InternalError"); std::string what = error.what(); EXPECT_NE(what.find("line"), std::string::npos); EXPECT_NE(what.find("2 > 3"), std::string::npos); @@ -64,7 +64,7 @@ TEST(CheckError, Traceback) { TEST(Error, AnyConvert) { Any any = Error("TypeError", "here", "test0"); Optional<Error> opt_err = any.as<Error>(); - EXPECT_STREQ(opt_err.value()->kind, "TypeError"); - EXPECT_STREQ(opt_err.value()->message, "here"); + EXPECT_EQ(opt_err.value().kind(), "TypeError"); + EXPECT_EQ(opt_err.value().message(), "here"); } } // namespace diff --git a/ffi/tests/cpp/test_function.cc b/ffi/tests/cpp/test_function.cc index d8895da934..fbdc580f3b 100644 --- a/ffi/tests/cpp/test_function.cc +++ b/ffi/tests/cpp/test_function.cc @@ -84,10 +84,10 @@ TEST(Func, FromUnpacked) { try { fadd1(1.1); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); - EXPECT_STREQ(error->message, - "Mismatched type on argument #0 when calling: `(0: int) -> int`. " - "Expected `int` but got `float`"); + EXPECT_EQ(error.kind(), "TypeError"); + EXPECT_EQ(error.message(), + "Mismatched type on argument #0 when calling: `(0: int) -> int`. " + "Expected `int` but got `float`"); throw; } }, @@ -99,10 +99,10 @@ TEST(Func, FromUnpacked) { try { fadd1(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); - EXPECT_STREQ(error->message, - "Mismatched number of arguments when calling: `(0: int) -> int`. " - "Expected 1 but got 0 arguments"); + EXPECT_EQ(error.kind(), "TypeError"); + EXPECT_EQ(error.message(), + "Mismatched number of arguments when calling: `(0: int) -> int`. " + "Expected 1 but got 0 arguments"); throw; } }, @@ -128,11 +128,11 @@ TEST(Func, FromUnpacked) { try { fpass_and_return(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); - EXPECT_STREQ(error->message, - "Mismatched number of arguments when calling: " - "`fpass_and_return(0: test.Int, 1: int, 2: AnyView) -> object.Function`. " - "Expected 3 but got 0 arguments"); + EXPECT_EQ(error.kind(), "TypeError"); + EXPECT_EQ(error.message(), + "Mismatched number of arguments when calling: " + "`fpass_and_return(0: test.Int, 1: int, 2: AnyView) -> object.Function`. " + "Expected 3 but got 0 arguments"); throw; } }, @@ -225,9 +225,9 @@ TEST(Func, ObjectRefWithFallbackTraits) { try { freturn_primexpr(TInt(1)); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); - EXPECT_STREQ( - error->message, + EXPECT_EQ(error.kind(), "TypeError"); + EXPECT_EQ( + error.message(), "Mismatched type on argument #0 when calling: `(0: test.PrimExpr) -> test.PrimExpr`. " "Expected `test.PrimExpr` but got `test.Int`"); throw; diff --git a/ffi/tests/cpp/test_map.cc b/ffi/tests/cpp/test_map.cc index aa449141be..1c43230bbc 100644 --- a/ffi/tests/cpp/test_map.cc +++ b/ffi/tests/cpp/test_map.cc @@ -215,7 +215,7 @@ TEST(Map, AnyConvertCheck) { try { [[maybe_unused]] auto arr2 = any1.cast<WrongMap>(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); + EXPECT_EQ(error.kind(), "TypeError"); std::string what = error.what(); EXPECT_NE( what.find( @@ -232,7 +232,7 @@ TEST(Map, AnyConvertCheck) { try { [[maybe_unused]] auto arr2 = any1.cast<WrongMap2>(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); + EXPECT_EQ(error.kind(), "TypeError"); std::string what = error.what(); EXPECT_NE(what.find("Cannot convert from type `Map[some key is int, V]` to " "`Map<test.Number, float>`"), diff --git a/ffi/tests/cpp/test_optional.cc b/ffi/tests/cpp/test_optional.cc index a45a391904..256a7da8b4 100644 --- a/ffi/tests/cpp/test_optional.cc +++ b/ffi/tests/cpp/test_optional.cc @@ -104,7 +104,7 @@ TEST(Optional, AnyConvert_Array) { try { [[maybe_unused]] auto arr2 = view0.cast<Optional<Array<Array<int>>>>(); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); + EXPECT_EQ(error.kind(), "TypeError"); std::string what = error.what(); std::cout << what << std::endl; EXPECT_NE(what.find("to `Optional<Array<Array<int>>>`"), std::string::npos); diff --git a/ffi/tests/cpp/test_rvalue_ref.cc b/ffi/tests/cpp/test_rvalue_ref.cc index d3a82c7158..ac81208d48 100644 --- a/ffi/tests/cpp/test_rvalue_ref.cc +++ b/ffi/tests/cpp/test_rvalue_ref.cc @@ -56,10 +56,10 @@ TEST(RValueRef, ParamChecking) { try { fadd1(RValueRef(TInt(1))); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); - EXPECT_STREQ(error->message, - "Mismatched type on argument #0 when calling: `(0: test.Int) -> int`. " - "Expected `test.Int` but got `ObjectRValueRef`"); + EXPECT_EQ(error.kind(), "TypeError"); + EXPECT_EQ(error.message(), + "Mismatched type on argument #0 when calling: `(0: test.Int) -> int`. " + "Expected `test.Int` but got `ObjectRValueRef`"); throw; } }, @@ -76,9 +76,9 @@ TEST(RValueRef, ParamChecking) { try { fadd2(RValueRef(Array<Any>({1, 2.2}))); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); - EXPECT_STREQ( - error->message, + EXPECT_EQ(error.kind(), "TypeError"); + EXPECT_EQ( + error.message(), "Mismatched type on argument #0 when calling: `(0: RValueRef<Array<int>>) -> int`. " "Expected `RValueRef<Array<int>>` but got `RValueRef<Array[index 1: float]>`"); throw; diff --git a/ffi/tests/cpp/test_tuple.cc b/ffi/tests/cpp/test_tuple.cc index 02a258522c..42c8e6aacc 100644 --- a/ffi/tests/cpp/test_tuple.cc +++ b/ffi/tests/cpp/test_tuple.cc @@ -101,11 +101,11 @@ TEST(Tuple, FromUnpacked) { try { fadd1(Array<Any>({1.1, 2})); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); - EXPECT_STREQ(error->message, - "Mismatched type on argument #0 when calling: `(0: Tuple<int, " - "test.PrimExpr>) -> int`. " - "Expected `Tuple<int, test.PrimExpr>` but got `Array[index 0: float]`"); + EXPECT_EQ(error.kind(), "TypeError"); + EXPECT_EQ(error.message(), + "Mismatched type on argument #0 when calling: `(0: Tuple<int, " + "test.PrimExpr>) -> int`. " + "Expected `Tuple<int, test.PrimExpr>` but got `Array[index 0: float]`"); throw; } }, @@ -116,11 +116,11 @@ TEST(Tuple, FromUnpacked) { try { fadd1(Array<Any>({1.1})); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); - EXPECT_STREQ(error->message, - "Mismatched type on argument #0 when calling: `(0: Tuple<int, " - "test.PrimExpr>) -> int`. " - "Expected `Tuple<int, test.PrimExpr>` but got `Array[size=1]`"); + EXPECT_EQ(error.kind(), "TypeError"); + EXPECT_EQ(error.message(), + "Mismatched type on argument #0 when calling: `(0: Tuple<int, " + "test.PrimExpr>) -> int`. " + "Expected `Tuple<int, test.PrimExpr>` but got `Array[size=1]`"); throw; } }, diff --git a/ffi/tests/cpp/test_variant.cc b/ffi/tests/cpp/test_variant.cc index db29bdac50..94cbcd491a 100644 --- a/ffi/tests/cpp/test_variant.cc +++ b/ffi/tests/cpp/test_variant.cc @@ -90,9 +90,9 @@ TEST(Variant, FromUnpacked) { try { fadd1(1.1); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); - EXPECT_STREQ( - error->message, + EXPECT_EQ(error.kind(), "TypeError"); + EXPECT_EQ( + error.message(), "Mismatched type on argument #0 when calling: `(0: Variant<int, test.Int>) -> int`. " "Expected `Variant<int, test.Int>` but got `float`"); throw; @@ -116,11 +116,11 @@ TEST(Variant, FromUnpacked) { try { fadd2(Array<Any>({1, 1.1})); } catch (const Error& error) { - EXPECT_STREQ(error->kind, "TypeError"); - EXPECT_STREQ(error->message, - "Mismatched type on argument #0 when calling: `(0: Array<Variant<int, " - "test.Int>>) -> int`. " - "Expected `Array<Variant<int, test.Int>>` but got `Array[index 1: float]`"); + EXPECT_EQ(error.kind(), "TypeError"); + EXPECT_EQ(error.message(), + "Mismatched type on argument #0 when calling: `(0: Array<Variant<int, " + "test.Int>>) -> int`. " + "Expected `Array<Variant<int, test.Int>>` but got `Array[index 1: float]`"); throw; } }, diff --git a/python/tvm/ffi/cython/base.pxi b/python/tvm/ffi/cython/base.pxi index 5c04e3316a..42db97809d 100644 --- a/python/tvm/ffi/cython/base.pxi +++ b/python/tvm/ffi/cython/base.pxi @@ -125,9 +125,9 @@ cdef extern from "tvm/ffi/c_api.h": size_t size ctypedef struct TVMFFIErrorCell: - const char* kind - const char* message - const char* traceback + TVMFFIByteArray kind + TVMFFIByteArray message + TVMFFIByteArray traceback ctypedef int (*TVMFFISafeCallType)( void* ctx, const TVMFFIAny* args, int32_t num_args, @@ -140,19 +140,18 @@ cdef extern from "tvm/ffi/c_api.h": int TVMFFIFunctionCreate(void* self, TVMFFISafeCallType safe_call, void (*deleter)(void*), TVMFFIObjectHandle* out) nogil int TVMFFIAnyViewToOwnedAny(const TVMFFIAny* any_view, TVMFFIAny* out) nogil - int TVMFFIFunctionSetGlobal(const char* name, TVMFFIObjectHandle f, int override) nogil - int TVMFFIFunctionGetGlobal(const char* name, TVMFFIObjectHandle* out) nogil + int TVMFFIFunctionSetGlobal(TVMFFIByteArray* name, TVMFFIObjectHandle f, int override) nogil + int TVMFFIFunctionGetGlobal(TVMFFIByteArray* name, TVMFFIObjectHandle* out) nogil void TVMFFIErrorMoveFromRaised(TVMFFIObjectHandle* result) nogil void TVMFFIErrorSetRaised(TVMFFIObjectHandle error) nogil - void TVMFFIErrorSetRaisedCStr(const char* kind, const char* message) nogil - void TVMFFIErrorUpdateTraceback(TVMFFIObjectHandle error, const char* traceback) nogil - int TVMFFIErrorCreate(const char* kind, const char* message, const char* traceback, - TVMFFIObjectHandle* out) nogil - int TVMFFIEnvRegisterCAPI(const char* name, void* ptr) nogil - int TVMFFITypeKeyToIndex(const char* type_key, int32_t* out_tindex) nogil - int TVMFFIDataTypeFromString(const char* str, DLDataType* out) nogil + void TVMFFIErrorUpdateTraceback(TVMFFIObjectHandle error, TVMFFIByteArray* traceback) nogil + TVMFFIObjectHandle TVMFFIErrorCreate(TVMFFIByteArray* kind, TVMFFIByteArray* message, + TVMFFIByteArray* traceback) nogil + int TVMFFIEnvRegisterCAPI(TVMFFIByteArray* name, void* ptr) nogil + int TVMFFITypeKeyToIndex(TVMFFIByteArray* type_key, int32_t* out_tindex) nogil + int TVMFFIDataTypeFromString(TVMFFIByteArray* str, DLDataType* out) nogil int TVMFFIDataTypeToString(DLDataType dtype, TVMFFIObjectHandle* out) nogil - const char* TVMFFITraceback(const char* filename, int lineno, const char* func) nogil; + const TVMFFIByteArray* TVMFFITraceback(const char* filename, int lineno, const char* func) nogil; int TVMFFINDArrayFromDLPack(DLManagedTensor* src, int32_t require_alignment, int32_t require_contiguous, TVMFFIObjectHandle* out) nogil int TVMFFINDArrayFromDLPackVersioned(DLManagedTensorVersioned* src, @@ -169,6 +168,24 @@ cdef extern from "tvm/ffi/c_api.h": DLDevice TVMFFIDLDeviceFromIntPair(int32_t device_type, int32_t device_id) nogil +cdef class ByteArrayArg: + cdef TVMFFIByteArray cdata + cdef object py_data + + def __cinit__(self, py_data): + if isinstance(py_data, bytearray): + py_data = bytes(py_data) + cdef char* data + cdef Py_ssize_t size + self.py_data = py_data + PyBytes_AsStringAndSize(py_data, &data, &size) + self.cdata.data = data + self.cdata.size = size + + cdef inline TVMFFIByteArray* cptr(self): + return &self.cdata + + cdef inline py_str(const char* x): """Convert a c_char_p to a python string @@ -180,6 +197,10 @@ cdef inline py_str(const char* x): return x.decode("utf-8") +cdef inline str bytearray_to_str(const TVMFFIByteArray* x): + return PyBytes_FromStringAndSize(x.data, x.size).decode("utf-8") + + cdef inline c_str(pystr): """Create ctypes char * from a python string @@ -212,8 +233,11 @@ cdef _init_env_api(): # Initialize env api for signal handling # Also registers the gil state release and ensure as PyErr_CheckSignals # function is called with gil released and we need to regrab the gil - CHECK_CALL(TVMFFIEnvRegisterCAPI(c_str("PyErr_CheckSignals"), <void*>PyErr_CheckSignals)) - CHECK_CALL(TVMFFIEnvRegisterCAPI(c_str("PyGILState_Ensure"), <void*>PyGILState_Ensure)) - CHECK_CALL(TVMFFIEnvRegisterCAPI(c_str("PyGILState_Release"), <void*>PyGILState_Release)) + cdef ByteArrayArg pyerr_check_signals_arg = ByteArrayArg(c_str("PyErr_CheckSignals")) + cdef ByteArrayArg pygilstate_ensure_arg = ByteArrayArg(c_str("PyGILState_Ensure")) + cdef ByteArrayArg pygilstate_release_arg = ByteArrayArg(c_str("PyGILState_Release")) + CHECK_CALL(TVMFFIEnvRegisterCAPI(pyerr_check_signals_arg.cptr(), <void*>PyErr_CheckSignals)) + CHECK_CALL(TVMFFIEnvRegisterCAPI(pygilstate_ensure_arg.cptr(), <void*>PyGILState_Ensure)) + CHECK_CALL(TVMFFIEnvRegisterCAPI(pygilstate_release_arg.cptr(), <void*>PyGILState_Release)) _init_env_api() diff --git a/python/tvm/ffi/cython/dtype.pxi b/python/tvm/ffi/cython/dtype.pxi index ef71ea4edd..30f9f274b4 100644 --- a/python/tvm/ffi/cython/dtype.pxi +++ b/python/tvm/ffi/cython/dtype.pxi @@ -44,7 +44,8 @@ cdef class DataType: cdef DLDataType cdtype def __init__(self, dtype_str): - CHECK_CALL(TVMFFIDataTypeFromString(c_str(dtype_str), &(self.cdtype))) + cdef ByteArrayArg dtype_str_arg = ByteArrayArg(c_str(dtype_str)) + CHECK_CALL(TVMFFIDataTypeFromString(dtype_str_arg.cptr(), &(self.cdtype))) def __reduce__(self): cls = type(self) diff --git a/python/tvm/ffi/cython/error.pxi b/python/tvm/ffi/cython/error.pxi index ba1d930912..73aa86572d 100644 --- a/python/tvm/ffi/cython/error.pxi +++ b/python/tvm/ffi/cython/error.pxi @@ -73,10 +73,12 @@ cdef class Error(Object): """ def __init__(self, kind, message, traceback): - CHECK_CALL( - TVMFFIErrorCreate( - c_str(kind), c_str(message), c_str(traceback), - &(<Object>self).chandle)) + cdef ByteArrayArg kind_arg = ByteArrayArg(c_str(kind)) + cdef ByteArrayArg message_arg = ByteArrayArg(c_str(message)) + cdef ByteArrayArg traceback_arg = ByteArrayArg(c_str(traceback)) + (<Object>self).chandle = TVMFFIErrorCreate( + kind_arg.cptr(), message_arg.cptr(), traceback_arg.cptr() + ) def update_traceback(self, traceback): """Update the traceback of the error @@ -86,7 +88,8 @@ cdef class Error(Object): traceback : str The traceback to update. """ - TVMFFIErrorUpdateTraceback(self.chandle, c_str(traceback)) + cdef ByteArrayArg traceback_arg = ByteArrayArg(c_str(traceback)) + TVMFFIErrorUpdateTraceback(self.chandle, traceback_arg.cptr()) def py_error(self): """ @@ -100,15 +103,15 @@ cdef class Error(Object): @property def kind(self): - return py_str(TVMFFIErrorGetCellPtr(self.chandle).kind) + return bytearray_to_str(&(TVMFFIErrorGetCellPtr(self.chandle).kind)) @property def message(self): - return py_str(TVMFFIErrorGetCellPtr(self.chandle).message) + return bytearray_to_str(&(TVMFFIErrorGetCellPtr(self.chandle).message)) @property def traceback(self): - return py_str(TVMFFIErrorGetCellPtr(self.chandle).traceback) + return bytearray_to_str(&(TVMFFIErrorGetCellPtr(self.chandle).traceback)) _register_object_by_index(kTVMFFIError, Error) @@ -131,7 +134,7 @@ cdef inline int set_last_ffi_error(error) except -1: kind = ERROR_TYPE_TO_NAME.get(type(error), "RuntimeError") message = error.__str__() py_traceback = _TRACEBACK_TO_STR(error.__traceback__) - c_traceback = py_str(TVMFFITraceback("<unknown>", 0, "<unknown>")) + c_traceback = bytearray_to_str(TVMFFITraceback("<unknown>", 0, "<unknown>")) # error comes from an exception thrown from C++ side if hasattr(error, "__tvm_ffi_error__"): diff --git a/python/tvm/ffi/cython/function.pxi b/python/tvm/ffi/cython/function.pxi index 0c97c939e5..be80023c85 100644 --- a/python/tvm/ffi/cython/function.pxi +++ b/python/tvm/ffi/cython/function.pxi @@ -108,7 +108,7 @@ cdef inline int make_args(tuple py_args, TVMFFIAny* out, list temp_args) except arg = ByteArrayArg(arg) out[i].type_index = kTVMFFIByteArrayPtr out[i].v_int64 = 0 - out[i].v_ptr = &((<ByteArrayArg>arg).cdata) + out[i].v_ptr = (<ByteArrayArg>arg).cptr() temp_args.append(arg) elif isinstance(arg, (list, tuple, dict, ObjectGeneric)): arg = _FUNC_CONVERT_TO_OBJECT(arg) @@ -218,18 +218,20 @@ def _register_global_func(name, pyfunc, override): cdef TVMFFIObjectHandle chandle cdef int c_api_ret_code cdef int ioverride = override + cdef ByteArrayArg name_arg = ByteArrayArg(c_str(name)) if not isinstance(pyfunc, Function): pyfunc = _convert_to_ffi_func(pyfunc) - CHECK_CALL(TVMFFIFunctionSetGlobal(c_str(name), (<Object>pyfunc).chandle, ioverride)) + CHECK_CALL(TVMFFIFunctionSetGlobal(name_arg.cptr(), (<Object>pyfunc).chandle, ioverride)) return pyfunc def _get_global_func(name, allow_missing): cdef TVMFFIObjectHandle chandle + cdef ByteArrayArg name_arg = ByteArrayArg(c_str(name)) - CHECK_CALL(TVMFFIFunctionGetGlobal(c_str(name), &chandle)) + CHECK_CALL(TVMFFIFunctionGetGlobal(name_arg.cptr(), &chandle)) if chandle != NULL: ret = Function.__new__(Function) (<Object>ret).chandle = chandle diff --git a/python/tvm/ffi/cython/object.pxi b/python/tvm/ffi/cython/object.pxi index c258f578b0..f971ca8f5a 100644 --- a/python/tvm/ffi/cython/object.pxi +++ b/python/tvm/ffi/cython/object.pxi @@ -251,7 +251,8 @@ def _register_object_by_index(int index, object cls): def _object_type_key_to_index(str type_key): """get the type index of object class""" cdef int32_t tidx - if TVMFFITypeKeyToIndex(c_str(type_key), &tidx) == 0: + type_key_arg = ByteArrayArg(c_str(type_key)) + if TVMFFITypeKeyToIndex(type_key_arg.cptr(), &tidx) == 0: return tidx return None diff --git a/python/tvm/ffi/cython/string.pxi b/python/tvm/ffi/cython/string.pxi index 733ea90301..512aa7bace 100644 --- a/python/tvm/ffi/cython/string.pxi +++ b/python/tvm/ffi/cython/string.pxi @@ -28,20 +28,6 @@ cdef inline bytes _bytes_obj_get_py_bytes(obj): return PyBytes_FromStringAndSize(bytes.data, bytes.size) -cdef class ByteArrayArg: - cdef TVMFFIByteArray cdata - cdef object py_data - - def __cinit__(self, py_data): - if isinstance(py_data, bytearray): - py_data = bytes(py_data) - cdef char* data - cdef Py_ssize_t size - self.py_data = py_data - PyBytes_AsStringAndSize(py_data, &data, &size) - self.cdata.data = data - self.cdata.size = size - class String(str, PyNativeObject): __slots__ = ["__tvm_ffi_object__"] diff --git a/src/node/reflection.cc b/src/node/reflection.cc index b49440dce3..067f4abb20 100644 --- a/src/node/reflection.cc +++ b/src/node/reflection.cc @@ -168,7 +168,8 @@ ReflectionVTable* ReflectionVTable::Global() { ObjectPtr<Object> ReflectionVTable::CreateInitObject(const std::string& type_key, const std::string& repr_bytes) const { int32_t tindex; - TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(type_key.c_str(), &tindex)); + TVMFFIByteArray type_key_arr{type_key.data(), type_key.length()}; + TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(&type_key_arr, &tindex)); if (static_cast<size_t>(tindex) >= fcreate_.size() || fcreate_[tindex] == nullptr) { LOG(FATAL) << "TypeError: " << type_key << " is not registered via TVM_REGISTER_NODE_TYPE"; } diff --git a/src/runtime/c_runtime_api.cc b/src/runtime/c_runtime_api.cc index 542179d08b..0482f4ab70 100644 --- a/src/runtime/c_runtime_api.cc +++ b/src/runtime/c_runtime_api.cc @@ -434,10 +434,13 @@ void* TVMGetLastPythonError() { const char* TVMGetLastBacktrace() { const auto& last_error = TVMAPIRuntimeStore::Get()->last_error; + static thread_local std::string traceback; if (const auto* wrapped = std::get_if<WrappedPythonError>(&last_error)) { - return (*wrapped)->traceback; + traceback = wrapped->traceback(); + return traceback.c_str(); } else if (const auto* wrapped = std::get_if<InternalError>(&last_error)) { - return (*wrapped)->traceback; + traceback = wrapped->traceback(); + return traceback.c_str(); } else { return nullptr; } diff --git a/src/runtime/object_internal.h b/src/runtime/object_internal.h index 662e67e693..40e4e2fb48 100644 --- a/src/runtime/object_internal.h +++ b/src/runtime/object_internal.h @@ -74,7 +74,8 @@ class ObjectInternal { */ static uint32_t ObjectTypeKey2Index(const std::string& type_key) { int32_t type_index; - TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(type_key.c_str(), &type_index)); + TVMFFIByteArray type_key_arr{type_key.data(), type_key.length()}; + TVM_FFI_CHECK_SAFE_CALL(TVMFFITypeKeyToIndex(&type_key_arr, &type_index)); return static_cast<uint32_t>(type_index); } /*! diff --git a/src/target/target.cc b/src/target/target.cc index 143436541e..360c56642b 100644 --- a/src/target/target.cc +++ b/src/target/target.cc @@ -403,7 +403,7 @@ Any TargetInternal::ParseType(const std::string& str, const TargetKindNode::Valu result.push_back(parsed); } catch (const Error& e) { std::string index = "[" + std::to_string(result.size()) + "]"; - throw Error(e->kind, std::string(e->message) + index, e->traceback); + throw Error(e.kind(), e.message() + index, e.traceback()); } } return Array<ObjectRef>(result); @@ -449,7 +449,7 @@ Any TargetInternal::ParseType(const Any& obj, const TargetKindNode::ValueTypeInf result.push_back(TargetInternal::ParseType(e, *info.key).cast<ObjectRef>()); } catch (const Error& e) { std::string index = '[' + std::to_string(result.size()) + ']'; - throw Error(e->kind, index + e->message, e->traceback); + throw Error(e.kind(), index + e.message(), e.traceback()); } } return Array<ObjectRef>(result); @@ -462,14 +462,14 @@ Any TargetInternal::ParseType(const Any& obj, const TargetKindNode::ValueTypeInf try { key = TargetInternal::ParseType(kv.first, *info.key); } catch (const Error& e) { - throw Error(e->kind, std::string(e->message) + ", during parse key of map", e->traceback); + throw Error(e.kind(), e.message() + ", during parse key of map", e.traceback()); } try { val = TargetInternal::ParseType(kv.second, *info.val); } catch (const Error& e) { std::ostringstream os; os << ", during parseing value of map[\"" << key << "\"]"; - throw Error(e->kind, std::string(e->message) + os.str(), e->traceback); + throw Error(e.kind(), e.message() + os.str(), e.traceback()); } result[key] = val; } @@ -577,7 +577,7 @@ Target::Target(const String& tag_or_config_or_target_str) { } catch (const Error& e) { std::ostringstream os; os << ". Target creation from string failed: " << tag_or_config_or_target_str; - throw Error("ValueError", std::string(e->message) + os.str(), e->traceback); + throw Error("ValueError", e.message() + os.str(), e.traceback()); } data_ = std::move(target); } @@ -589,7 +589,7 @@ Target::Target(const Map<String, ffi::Any>& config) { } catch (const Error& e) { std::ostringstream os; os << ". Target creation from config dict failed: " << config; - throw Error("ValueError", std::string(e->message) + os.str(), e->traceback); + throw Error("ValueError", std::string(e.message()) + os.str(), e.traceback()); } data_ = std::move(target); } @@ -820,8 +820,8 @@ ObjectPtr<Object> TargetInternal::FromRawString(const String& target_str) { std::string s_next = (iter + 1 < options.size()) ? options[iter + 1] : ""; iter += ParseKVPair(RemovePrefixDashes(options[iter]), s_next, &key, &value); } catch (const Error& e) { - throw Error(e->kind, std::string(e->message) + ", during parsing target `" + target_str + "`", - e->traceback); + throw Error(e.kind(), e.message() + ", during parsing target `" + target_str + "`", + e.traceback()); } try { // check if `key` has been used @@ -830,8 +830,8 @@ ObjectPtr<Object> TargetInternal::FromRawString(const String& target_str) { } config[key] = TargetInternal::ParseType(value, TargetInternal::FindTypeInfo(kind, key)); } catch (const Error& e) { - throw Error(e->kind, std::string(e->message) + ", during parsing target[\"" + key + "\"]", - e->traceback); + throw Error(e.kind(), std::string(e.message()) + ", during parsing target[\"" + key + "\"]", + e.traceback()); } } return TargetInternal::FromConfig(config); @@ -937,8 +937,8 @@ ObjectPtr<Object> TargetInternal::FromConfig(Map<String, ffi::Any> config) { const TargetKindNode::ValueTypeInfo& info = TargetInternal::FindTypeInfo(target->kind, key); attrs[key] = TargetInternal::ParseType(value, info); } catch (const Error& e) { - throw Error(e->kind, std::string(e->message) + ", during parsing target[\"" + key + "\"]", - e->traceback); + throw Error(e.kind(), std::string(e.message()) + ", during parsing target[\"" + key + "\"]", + e.traceback()); } }
