This is an automated email from the ASF dual-hosted git repository. tqchen pushed a commit to branch refactor-s0 in repository https://gitbox.apache.org/repos/asf/tvm.git
commit b9e1fd8d256920506a85b91aee9be86f37884455 Author: tqchen <[email protected]> AuthorDate: Sun Mar 9 10:59:25 2025 -0400 First step, pass string compile --- ffi/include/tvm/ffi/c_api.h | 1 + ffi/include/tvm/ffi/object.h | 28 +- include/tvm/runtime/container/map.h | 4 +- include/tvm/runtime/container/string.h | 2 +- include/tvm/runtime/memory.h | 180 +---- include/tvm/runtime/{memory.h => memory_backup.h} | 0 include/tvm/runtime/object.h | 887 +--------------------- include/tvm/runtime/{object.h => object_backup.h} | 12 +- src/runtime/debug_compile.cc | 35 + 9 files changed, 99 insertions(+), 1050 deletions(-) diff --git a/ffi/include/tvm/ffi/c_api.h b/ffi/include/tvm/ffi/c_api.h index a1cf753448..44456aacd6 100644 --- a/ffi/include/tvm/ffi/c_api.h +++ b/ffi/include/tvm/ffi/c_api.h @@ -85,6 +85,7 @@ typedef enum { kTVMFFIShapeTuple = 70, kTVMFFINDArray = 71, kTVMFFIRuntimeModule = 72, + kTVMFFIStaticObjectEnd, // [Section] Dynamic Boxed: [kTVMFFIDynObjectBegin, +oo) // kTVMFFIDynObject is used to indicate that the type index // is dynamic and needs to be looked up at runtime diff --git a/ffi/include/tvm/ffi/object.h b/ffi/include/tvm/ffi/object.h index a7afb6c12f..4cb26f1c2b 100644 --- a/ffi/include/tvm/ffi/object.h +++ b/ffi/include/tvm/ffi/object.h @@ -147,7 +147,7 @@ class Object { */ static int32_t _GetOrAllocRuntimeTypeIndex() { return TypeIndex::kTVMFFIObject; } - private: + private: /*! \brief increase reference count */ void IncRef() { details::AtomicIncrementRelaxed(&(header_.ref_counter)); } @@ -408,6 +408,26 @@ class ObjectRef { template <typename BaseType, typename ObjectType> inline ObjectPtr<BaseType> GetObjectPtr(ObjectType* ptr); +/*! \brief ObjectRef hash functor */ +struct ObjectPtrHash { + size_t operator()(const ObjectRef& a) const { return operator()(a.data_); } + + template <typename T> + size_t operator()(const ObjectPtr<T>& a) const { + return std::hash<Object*>()(a.get()); + } +}; + +/*! \brief ObjectRef equal functor */ +struct ObjectPtrEqual { + bool operator()(const ObjectRef& a, const ObjectRef& b) const { return a.same_as(b); } + + template <typename T> + size_t operator()(const ObjectPtr<T>& a, const ObjectPtr<T>& b) const { + return a == b; + } +}; + /*! * \brief Helper macro to declare list of static checks about object meta-data. * \param TypeName The name of the current type. @@ -599,7 +619,13 @@ class ObjectUnsafe { *ref = nullptr; return ptr; } + + // legacy APIs to support migration and can be moved later + static TVM_FFI_INLINE void LegacyClearObjectPtrAfterMove(ObjectRef* src) { + src->data_.data_ = nullptr; + } }; + } // namespace details } // namespace ffi } // namespace tvm diff --git a/include/tvm/runtime/container/map.h b/include/tvm/runtime/container/map.h index eb86ddb7b8..1e4015aa23 100644 --- a/include/tvm/runtime/container/map.h +++ b/include/tvm/runtime/container/map.h @@ -1251,8 +1251,8 @@ inline void MapNode::InsertMaybeReHash(const KVType& kv, ObjectPtr<Object>* map) } } -template <> -inline ObjectPtr<MapNode> make_object<>() = delete; +//template <> +//inline ObjectPtr<MapNode> make_object<>() = delete; #endif diff --git a/include/tvm/runtime/container/string.h b/include/tvm/runtime/container/string.h index a7be84de23..661d95bba2 100644 --- a/include/tvm/runtime/container/string.h +++ b/include/tvm/runtime/container/string.h @@ -59,7 +59,7 @@ class StringObj : public Object { static constexpr const uint32_t _type_index = TypeIndex::kRuntimeString; static constexpr const char* _type_key = "runtime.String"; - TVM_DECLARE_FINAL_OBJECT_INFO(StringObj, Object); + TVM_FFI_DECLARE_STATIC_OBJECT_INFO(StringObj, Object); private: /*! \brief String object which is moved from std::string container. */ diff --git a/include/tvm/runtime/memory.h b/include/tvm/runtime/memory.h index 1199c420f2..adf7fe9a3a 100644 --- a/include/tvm/runtime/memory.h +++ b/include/tvm/runtime/memory.h @@ -17,190 +17,18 @@ * under the License. */ /*! - * \file tvm/runtime/memory.h - * \brief Runtime memory management. + * \file tvm/runtime/object.h + * \brief A managed object in the TVM runtime. */ #ifndef TVM_RUNTIME_MEMORY_H_ #define TVM_RUNTIME_MEMORY_H_ -#include <tvm/runtime/object.h> - -#include <cstdlib> -#include <type_traits> -#include <utility> +#include <tvm/ffi/memory.h> namespace tvm { namespace runtime { -/*! - * \brief Allocate an object using default allocator. - * \param args arguments to the constructor. - * \tparam T the node type. - * \return The ObjectPtr to the allocated object. - */ -template <typename T, typename... Args> -inline ObjectPtr<T> make_object(Args&&... args); - -// Detail implementations after this -// -// The current design allows swapping the -// allocator pattern when necessary. -// -// Possible future allocator optimizations: -// - Arena allocator that gives ownership of memory to arena (deleter_= nullptr) -// - Thread-local object pools: one pool per size and alignment requirement. -// - Can specialize by type of object to give the specific allocator to each object. - -/*! - * \brief Base class of object allocators that implements make. - * Use curiously recurring template pattern. - * - * \tparam Derived The derived class. - */ -template <typename Derived> -class ObjAllocatorBase { - public: - /*! - * \brief Make a new object using the allocator. - * \tparam T The type to be allocated. - * \tparam Args The constructor signature. - * \param args The arguments. - */ - template <typename T, typename... Args> - inline ObjectPtr<T> make_object(Args&&... args) { - using Handler = typename Derived::template Handler<T>; - static_assert(std::is_base_of<Object, T>::value, "make can only be used to create Object"); - T* ptr = Handler::New(static_cast<Derived*>(this), std::forward<Args>(args)...); - ptr->type_index_ = T::RuntimeTypeIndex(); - ptr->deleter_ = Handler::Deleter(); - return ObjectPtr<T>(ptr); - } - - /*! - * \tparam ArrayType The type to be allocated. - * \tparam ElemType The type of array element. - * \tparam Args The constructor signature. - * \param num_elems The number of array elements. - * \param args The arguments. - */ - template <typename ArrayType, typename ElemType, typename... Args> - inline ObjectPtr<ArrayType> make_inplace_array(size_t num_elems, Args&&... args) { - using Handler = typename Derived::template ArrayHandler<ArrayType, ElemType>; - static_assert(std::is_base_of<Object, ArrayType>::value, - "make_inplace_array can only be used to create Object"); - ArrayType* ptr = - Handler::New(static_cast<Derived*>(this), num_elems, std::forward<Args>(args)...); - ptr->type_index_ = ArrayType::RuntimeTypeIndex(); - ptr->deleter_ = Handler::Deleter(); - return ObjectPtr<ArrayType>(ptr); - } -}; - -// Simple allocator that uses new/delete. -class SimpleObjAllocator : public ObjAllocatorBase<SimpleObjAllocator> { - public: - template <typename T> - class Handler { - public: - using StorageType = typename std::aligned_storage<sizeof(T), alignof(T)>::type; - - template <typename... Args> - static T* New(SimpleObjAllocator*, Args&&... args) { - // NOTE: the first argument is not needed for SimpleObjAllocator - // It is reserved for special allocators that needs to recycle - // the object to itself (e.g. in the case of object pool). - // - // In the case of an object pool, an allocator needs to create - // a special chunk memory that hides reference to the allocator - // and call allocator's release function in the deleter. - - // NOTE2: Use inplace new to allocate - // This is used to get rid of warning when deleting a virtual - // class with non-virtual destructor. - // We are fine here as we captured the right deleter during construction. - // This is also the right way to get storage type for an object pool. - StorageType* data = new StorageType(); - new (data) T(std::forward<Args>(args)...); - return reinterpret_cast<T*>(data); - } - - static Object::FDeleter Deleter() { return Deleter_; } - - private: - static void Deleter_(Object* objptr) { - // NOTE: this is important to cast back to T* - // because objptr and tptr may not be the same - // depending on how sub-class allocates the space. - T* tptr = static_cast<T*>(objptr); - // It is important to do tptr->T::~T(), - // so that we explicitly call the specific destructor - // instead of tptr->~T(), which could mean the intention - // call a virtual destructor(which may not be available and is not required). - tptr->T::~T(); - delete reinterpret_cast<StorageType*>(tptr); - } - }; - - // Array handler that uses new/delete. - template <typename ArrayType, typename ElemType> - class ArrayHandler { - public: - using StorageType = typename std::aligned_storage<sizeof(ArrayType), alignof(ArrayType)>::type; - // for now only support elements that aligns with array header. - static_assert(alignof(ArrayType) % alignof(ElemType) == 0 && - sizeof(ArrayType) % alignof(ElemType) == 0, - "element alignment constraint"); - - template <typename... Args> - static ArrayType* New(SimpleObjAllocator*, size_t num_elems, Args&&... args) { - // NOTE: the first argument is not needed for ArrayObjAllocator - // It is reserved for special allocators that needs to recycle - // the object to itself (e.g. in the case of object pool). - // - // In the case of an object pool, an allocator needs to create - // a special chunk memory that hides reference to the allocator - // and call allocator's release function in the deleter. - // NOTE2: Use inplace new to allocate - // This is used to get rid of warning when deleting a virtual - // class with non-virtual destructor. - // We are fine here as we captured the right deleter during construction. - // This is also the right way to get storage type for an object pool. - size_t unit = sizeof(StorageType); - size_t requested_size = num_elems * sizeof(ElemType) + sizeof(ArrayType); - size_t num_storage_slots = (requested_size + unit - 1) / unit; - StorageType* data = new StorageType[num_storage_slots]; - new (data) ArrayType(std::forward<Args>(args)...); - return reinterpret_cast<ArrayType*>(data); - } - - static Object::FDeleter Deleter() { return Deleter_; } - - private: - static void Deleter_(Object* objptr) { - // NOTE: this is important to cast back to ArrayType* - // because objptr and tptr may not be the same - // depending on how sub-class allocates the space. - ArrayType* tptr = static_cast<ArrayType*>(objptr); - // It is important to do tptr->ArrayType::~ArrayType(), - // so that we explicitly call the specific destructor - // instead of tptr->~ArrayType(), which could mean the intention - // call a virtual destructor(which may not be available and is not required). - tptr->ArrayType::~ArrayType(); - StorageType* p = reinterpret_cast<StorageType*>(tptr); - delete[] p; - } - }; -}; - -template <typename T, typename... Args> -inline ObjectPtr<T> make_object(Args&&... args) { - return SimpleObjAllocator().make_object<T>(std::forward<Args>(args)...); -} -template <typename ArrayType, typename ElemType, typename... Args> -inline ObjectPtr<ArrayType> make_inplace_array_object(size_t num_elems, Args&&... args) { - return SimpleObjAllocator().make_inplace_array<ArrayType, ElemType>(num_elems, - std::forward<Args>(args)...); -} +using namespace tvm::ffi; } // namespace runtime } // namespace tvm diff --git a/include/tvm/runtime/memory.h b/include/tvm/runtime/memory_backup.h similarity index 100% copy from include/tvm/runtime/memory.h copy to include/tvm/runtime/memory_backup.h diff --git a/include/tvm/runtime/object.h b/include/tvm/runtime/object.h index 527d663c02..c2b3681bc4 100644 --- a/include/tvm/runtime/object.h +++ b/include/tvm/runtime/object.h @@ -23,588 +23,52 @@ #ifndef TVM_RUNTIME_OBJECT_H_ #define TVM_RUNTIME_OBJECT_H_ -#include <tvm/runtime/c_runtime_api.h> -#include <tvm/runtime/logging.h> #include <tvm/ffi/object.h> - -#include <string> -#include <type_traits> -#include <utility> - -/*! - * \brief Whether or not use atomic reference counter. - * If the reference counter is not atomic, - * an object cannot be owned by multiple threads. - * We can, however, move an object across threads - */ -#ifndef TVM_OBJECT_ATOMIC_REF_COUNTER -#define TVM_OBJECT_ATOMIC_REF_COUNTER 1 -#endif - -#if TVM_OBJECT_ATOMIC_REF_COUNTER -#include <atomic> -#endif // TVM_OBJECT_ATOMIC_REF_COUNTER +#include <tvm/ffi/cast.h> +#include <tvm/ffi/reflection.h> namespace tvm { namespace runtime { +using namespace tvm::ffi; + /*! * \brief Namespace for the list of type index. * \note Use struct so that we have to use TypeIndex::ENumName to refer to * the constant, but still able to use enum. */ -struct TypeIndex { - enum { - /*! \brief Root object type. */ - kRoot = 0, +enum TypeIndex : int32_t { // Standard static index assignments, // Frontends can take benefit of these constants. + kRuntimeString = TVMFFITypeIndex::kTVMFFIStr, + kRuntimeMap = TVMFFITypeIndex::kTVMFFIMap, + kRuntimeArray = TVMFFITypeIndex::kTVMFFIArray, /*! \brief runtime::Module. */ - kRuntimeModule = 1, + kRuntimeModule = TVMFFITypeIndex::kTVMFFIRuntimeModule, /*! \brief runtime::NDArray. */ - kRuntimeNDArray = 2, - /*! \brief runtime::String. */ - kRuntimeString = 3, - /*! \brief runtime::Array. */ - kRuntimeArray = 4, - /*! \brief runtime::Map. */ - kRuntimeMap = 5, + kRuntimeNDArray = TVMFFITypeIndex::kTVMFFINDArray, /*! \brief runtime::ShapeTuple. */ - kRuntimeShapeTuple = 6, + kRuntimeShapeTuple = TVMFFITypeIndex::kTVMFFIShapeTuple, + // Extra builtin static index here + kCustomStaticIndex = TVMFFITypeIndex::kTVMFFIStaticObjectEnd, /*! \brief runtime::PackedFunc. */ - kRuntimePackedFunc = 7, + kRuntimePackedFunc = kCustomStaticIndex + 1, /*! \brief runtime::DRef for disco distributed runtime */ - kRuntimeDiscoDRef = 8, + kRuntimeDiscoDRef = kCustomStaticIndex + 2, /*! \brief runtime::RPCObjectRef */ - kRuntimeRPCObjectRef = 9, + kRuntimeRPCObjectRef = kCustomStaticIndex + 3, // static assignments that may subject to change. - kStaticIndexEnd = 10, - /*! - * \brief Type index is allocated during runtime, keeping it as - * constant for now to ensure compatibility across versions - */ - kDynamic = 12 - }; -}; // namespace TypeIndex - -/*! - * \brief base class of all object containers. - * - * Sub-class of objects should declare the following static constexpr fields: - * - * - _type_index: - * Static type index of the object, if assigned to TypeIndex::kDynamic - * the type index will be assigned during runtime. - * Runtime type index can be accessed by ObjectType::TypeIndex(); - * - _type_key: - * The unique string identifier of the type. - * - _type_final: - * Whether the type is terminal type(there is no subclass of the type in the object system). - * This field is automatically set by macro TVM_DECLARE_FINAL_OBJECT_INFO - * It is still OK to sub-class a terminal object type T and construct it using make_object. - * But IsInstance check will only show that the object type is T(instead of the sub-class). - * - * The following two fields are necessary for base classes that can be sub-classed. - * - * - _type_child_slots: - * Number of reserved type index slots for child classes. - * Used for runtime optimization for type checking in IsInstance. - * If an object's type_index is within range of [type_index, type_index + _type_child_slots] - * Then the object can be quickly decided as sub-class of the current object class. - * If not, a fallback mechanism is used to check the global type table. - * Recommendation: set to estimate number of children needed. - * - _type_child_slots_can_overflow: - * Whether we can add additional child classes even if the number of child classes - * exceeds the _type_child_slots. A fallback mechanism to check global type table will be - * used. Recommendation: set to false for optimal runtime speed if we know exact number of children. - * - * Two macros are used to declare helper functions in the object: - * - Use TVM_DECLARE_BASE_OBJECT_INFO for object classes that can be sub-classed. - * - Use TVM_DECLARE_FINAL_OBJECT_INFO for object classes that cannot be sub-classed. - * - * New objects can be created using make_object function. - * Which will automatically populate the type_index and deleter of the object. - * - * \sa make_object - * \sa ObjectPtr - * \sa ObjectRef - * - * \code - * - * // Create a base object - * class BaseObj : public Object { - * public: - * // object fields - * int field0; - * - * // object properties - * static constexpr const uint32_t _type_index = TypeIndex::kDynamic; - * static constexpr const char* _type_key = "test.BaseObj"; - * TVM_DECLARE_BASE_OBJECT_INFO(BaseObj, Object); - * }; - * - * class LeafObj : public BaseObj { - * public: - * // fields - * int child_field0; - * // object properties - * static constexpr const uint32_t _type_index = TypeIndex::kDynamic; - * static constexpr const char* _type_key = "test.LeafObj"; - * TVM_DECLARE_BASE_OBJECT_INFO(LeafObj, Object); - * }; - * - * // The following code should be put into a cc file. - * TVM_REGISTER_OBJECT_TYPE(BaseObj); - * TVM_REGISTER_OBJECT_TYPE(LeafObj); - * - * // Usage example. - * void TestObjects() { - * // create an object - * ObjectRef leaf_ref(make_object<LeafObj>()); - * // cast to a specific instance - * const LeafObj* leaf_ptr = leaf_ref.as<LeafObj>(); - * ICHECK(leaf_ptr != nullptr); - * // can also cast to the base class. - * ICHECK(leaf_ref.as<BaseObj>() != nullptr); - * } - * - * \endcode - */ -class TVM_DLL Object { - public: - /*! - * \brief Object deleter - * \param self pointer to the Object. - */ - typedef void (*FDeleter)(Object* self); - /*! \return The internal runtime type index of the object. */ - uint32_t type_index() const { return type_index_; } - /*! - * \return the type key of the object. - * \note this operation is expensive, can be used for error reporting. - */ - std::string GetTypeKey() const { return TypeIndex2Key(type_index_); } - /*! - * \return A hash value of the return of GetTypeKey. - */ - size_t GetTypeKeyHash() const { return TypeIndex2KeyHash(type_index_); } - /*! - * Check if the object is an instance of TargetType. - * \tparam TargetType The target type to be checked. - * \return Whether the target type is true. - */ - template <typename TargetType> - inline bool IsInstance() const; - /*! - * \return Whether the cell has only one reference - * \note We use stl style naming to be consistent with known API in shared_ptr. - */ - inline bool unique() const; - /*! - * \brief Get the type key of the corresponding index from runtime. - * \param tindex The type index. - * \return the result. - */ - static std::string TypeIndex2Key(uint32_t tindex); - /*! - * \brief Get the type key hash of the corresponding index from runtime. - * \param tindex The type index. - * \return the related key-hash. - */ - static size_t TypeIndex2KeyHash(uint32_t tindex); - /*! - * \brief Get the type index of the corresponding key from runtime. - * \param key The type key. - * \return the result. - */ - static uint32_t TypeKey2Index(const std::string& key); - -#if TVM_OBJECT_ATOMIC_REF_COUNTER - using RefCounterType = std::atomic<int32_t>; -#else - using RefCounterType = int32_t; -#endif - - static constexpr const char* _type_key = "runtime.Object"; - - static uint32_t _GetOrAllocRuntimeTypeIndex() { return TypeIndex::kRoot; } - static uint32_t RuntimeTypeIndex() { return TypeIndex::kRoot; } - - // Default object type properties for sub-classes - static constexpr bool _type_final = false; - static constexpr uint32_t _type_child_slots = 0; - static constexpr bool _type_child_slots_can_overflow = true; - // member information - static constexpr bool _type_has_method_visit_attrs = true; - static constexpr bool _type_has_method_sequal_reduce = false; - static constexpr bool _type_has_method_shash_reduce = false; - // NOTE: the following field is not type index of Object - // but was intended to be used by sub-classes as default value. - // The type index of Object is TypeIndex::kRoot - static constexpr uint32_t _type_index = TypeIndex::kDynamic; - - // Default constructor and copy constructor - Object() {} - // Override the copy and assign constructors to do nothing. - // This is to make sure only contents, but not deleter and ref_counter - // are copied when a child class copies itself. - // This will enable us to use make_object<ObjectClass>(*obj_ptr) - // to copy an existing object. - Object(const Object& other) { // NOLINT(*) - } - Object(Object&& other) { // NOLINT(*) - } - Object& operator=(const Object& other) { // NOLINT(*) - return *this; - } - Object& operator=(Object&& other) { // NOLINT(*) - return *this; - } - - protected: - // The fields of the base object cell. - /*! \brief Type index(tag) that indicates the type of the object. */ - uint32_t type_index_{0}; - /*! \brief The internal reference counter */ - RefCounterType ref_counter_{0}; - /*! - * \brief deleter of this object to enable customized allocation. - * If the deleter is nullptr, no deletion will be performed. - * The creator of the object must always set the deleter field properly. - */ - FDeleter deleter_ = nullptr; - // Invariant checks. - static_assert(sizeof(int32_t) == sizeof(RefCounterType) && - alignof(int32_t) == sizeof(RefCounterType), - "RefCounter ABI check."); - - /*! - * \brief Get the type index using type key. - * - * When the function is first time called for a type, - * it will register the type to the type table in the runtime. - * If the static_tindex is TypeIndex::kDynamic, the function will - * allocate a runtime type index. - * Otherwise, we will populate the type table and return the static index. - * - * \param key the type key. - * \param static_tindex The current _type_index field. - * can be TypeIndex::kDynamic. - * \param parent_tindex The index of the parent. - * \param type_child_slots Number of slots reserved for its children. - * \param type_child_slots_can_overflow Whether to allow child to overflow the slots. - * \return The allocated type index. - */ - static uint32_t GetOrAllocRuntimeTypeIndex(const std::string& key, uint32_t static_tindex, - uint32_t parent_tindex, uint32_t type_child_slots, - bool type_child_slots_can_overflow); - - // reference counter related operations - /*! \brief developer function, increases reference counter. */ - inline void IncRef(); - /*! - * \brief developer function, decrease reference counter. - * \note The deleter will be called when ref_counter_ becomes zero. - */ - inline void DecRef(); - - private: - /*! - * \return The usage count of the cell. - * \note We use stl style naming to be consistent with known API in shared_ptr. - */ - inline int use_count() const; - /*! - * \brief Check of this object is derived from the parent. - * \param parent_tindex The parent type index. - * \return The derivation results. - */ - bool DerivedFrom(uint32_t parent_tindex) const; - // friend classes - template <typename> - friend class ObjAllocatorBase; - template <typename> - friend class ObjectPtr; - friend class TVMRetValue; - friend class ObjectInternal; -}; - -/*! - * \brief Get a reference type from a raw object ptr type - * - * It is always important to get a reference type - * if we want to return a value as reference or keep - * the object alive beyond the scope of the function. - * - * \param ptr The object pointer - * \tparam RefType The reference type - * \tparam ObjectType The object type - * \return The corresponding RefType - */ -template <typename ObjectRefType, typename ObjectType> -inline ObjectRefType GetRef(const ObjectType* ptr); - -/*! - * \brief Downcast a base reference type to a more specific type. - * - * \param ref The input reference - * \return The corresponding SubRef. - * \tparam SubRef The target specific reference type. - * \tparam BaseRef the current reference type. - */ -template <typename SubRef, typename BaseRef> -inline SubRef Downcast(BaseRef ref); - -/*! - * \brief A custom smart pointer for Object. - * \tparam T the content data type. - * \sa make_object - */ -template <typename T> -class ObjectPtr { - public: - /*! \brief default constructor */ - ObjectPtr() {} - /*! \brief default constructor */ - ObjectPtr(std::nullptr_t) {} // NOLINT(*) - /*! - * \brief copy constructor - * \param other The value to be moved - */ - ObjectPtr(const ObjectPtr<T>& other) // NOLINT(*) - : ObjectPtr(other.data_) {} - /*! - * \brief copy constructor - * \param other The value to be moved - */ - template <typename U> - ObjectPtr(const ObjectPtr<U>& other) // NOLINT(*) - : ObjectPtr(other.data_) { - static_assert(std::is_base_of<T, U>::value, - "can only assign of child class ObjectPtr to parent"); - } - /*! - * \brief move constructor - * \param other The value to be moved - */ - ObjectPtr(ObjectPtr<T>&& other) // NOLINT(*) - : data_(other.data_) { - other.data_ = nullptr; - } - /*! - * \brief move constructor - * \param other The value to be moved - */ - template <typename Y> - ObjectPtr(ObjectPtr<Y>&& other) // NOLINT(*) - : data_(other.data_) { - static_assert(std::is_base_of<T, Y>::value, - "can only assign of child class ObjectPtr to parent"); - other.data_ = nullptr; - } - /*! \brief destructor */ - ~ObjectPtr() { this->reset(); } - /*! - * \brief Swap this array with another Object - * \param other The other Object - */ - void swap(ObjectPtr<T>& other) { // NOLINT(*) - std::swap(data_, other.data_); - } - /*! - * \return Get the content of the pointer - */ - T* get() const { return static_cast<T*>(data_); } - /*! - * \return The pointer - */ - T* operator->() const { return get(); } - /*! - * \return The reference - */ - T& operator*() const { // NOLINT(*) - return *get(); - } - /*! - * \brief copy assignment - * \param other The value to be assigned. - * \return reference to self. - */ - ObjectPtr<T>& operator=(const ObjectPtr<T>& other) { // NOLINT(*) - // takes in plane operator to enable copy elison. - // copy-and-swap idiom - ObjectPtr(other).swap(*this); // NOLINT(*) - return *this; - } - /*! - * \brief move assignment - * \param other The value to be assigned. - * \return reference to self. - */ - ObjectPtr<T>& operator=(ObjectPtr<T>&& other) { // NOLINT(*) - // copy-and-swap idiom - ObjectPtr(std::move(other)).swap(*this); // NOLINT(*) - return *this; - } - /*! - * \brief nullptr check - * \return result of comparison of internal pointer with nullptr. - */ - explicit operator bool() const { return get() != nullptr; } - /*! \brief reset the content of ptr to be nullptr */ - void reset() { - if (data_ != nullptr) { - data_->DecRef(); - data_ = nullptr; - } - } - /*! \return The use count of the ptr, for debug purposes */ - int use_count() const { return data_ != nullptr ? data_->use_count() : 0; } - /*! \return whether the reference is unique */ - bool unique() const { return data_ != nullptr && data_->use_count() == 1; } - /*! \return Whether two ObjectPtr do not equal each other */ - bool operator==(const ObjectPtr<T>& other) const { return data_ == other.data_; } - /*! \return Whether two ObjectPtr equals each other */ - bool operator!=(const ObjectPtr<T>& other) const { return data_ != other.data_; } - /*! \return Whether the pointer is nullptr */ - bool operator==(std::nullptr_t null) const { return data_ == nullptr; } - /*! \return Whether the pointer is not nullptr */ - bool operator!=(std::nullptr_t null) const { return data_ != nullptr; } - - private: - /*! \brief internal pointer field */ - Object* data_{nullptr}; - /*! - * \brief constructor from Object - * \param data The data pointer - */ - explicit ObjectPtr(Object* data) : data_(data) { - if (data != nullptr) { - data_->IncRef(); - } - } - /*! - * \brief Move an ObjectPtr from an RValueRef argument. - * \param ref The rvalue reference. - * \return the moved result. - */ - static ObjectPtr<T> MoveFromRValueRefArg(Object** ref) { - ObjectPtr<T> ptr; - ptr.data_ = *ref; - *ref = nullptr; - return ptr; - } - // friend classes - friend class Object; - friend class ObjectRef; - friend struct ObjectPtrHash; - template <typename> - friend class ObjectPtr; - template <typename> - friend class ObjAllocatorBase; - friend class TVMPODValue_; - friend class TVMArgsSetter; - friend class TVMRetValue; - friend class TVMArgValue; - friend class TVMMovableArgValue_; - template <typename ObjectRefType, typename ObjType> - friend ObjectRefType GetRef(const ObjType* ptr); - template <typename BaseType, typename ObjType> - friend ObjectPtr<BaseType> GetObjectPtr(ObjType* ptr); + kStaticIndexEnd }; -// Forward declaration, to prevent circular includes. -template <typename T> -class Optional; - -/*! \brief Base class of all object reference */ -class ObjectRef { +class ObjectRef : public tvm::ffi::ObjectRef { public: /*! \brief default constructor */ ObjectRef() = default; /*! \brief Constructor from existing object ptr */ - explicit ObjectRef(ObjectPtr<Object> data) : data_(data) {} - /*! - * \brief Comparator - * \param other Another object ref. - * \return the compare result. - */ - bool same_as(const ObjectRef& other) const { return data_ == other.data_; } - /*! - * \brief Comparator - * \param other Another object ref. - * \return the compare result. - */ - bool operator==(const ObjectRef& other) const { return data_ == other.data_; } - /*! - * \brief Comparator - * \param other Another object ref. - * \return the compare result. - */ - bool operator!=(const ObjectRef& other) const { return data_ != other.data_; } - /*! - * \brief Comparator - * \param other Another object ref by address. - * \return the compare result. - */ - bool operator<(const ObjectRef& other) const { return data_.get() < other.data_.get(); } - /*! - * \return whether the object is defined(not null). - */ - bool defined() const { return data_ != nullptr; } - /*! \return the internal object pointer */ - const Object* get() const { return data_.get(); } - /*! \return the internal object pointer */ - const Object* operator->() const { return get(); } - /*! \return whether the reference is unique */ - bool unique() const { return data_.unique(); } - /*! \return The use count of the ptr, for debug purposes */ - int use_count() const { return data_.use_count(); } - - /*! - * \brief Try to downcast the internal Object to a - * raw pointer of a corresponding type. - * - * The function will return a nullptr if the cast failed. - * - * if (const AddNode *ptr = node_ref.as<AddNode>()) { - * // This is an add node - * } - * - * \tparam ObjectType the target type, must be a subtype of Object - */ - template <typename ObjectType, typename = std::enable_if_t<std::is_base_of_v<Object, ObjectType>>> - inline const ObjectType* as() const; - - /*! - * \brief Try to downcast the ObjectRef to a - * Optional<T> of the requested type. - * - * The function will return a NullOpt if the cast failed. - * - * if (Optional<Add> opt = node_ref.as<Add>()) { - * // This is an add node - * } - * - * \note While this method is declared in <tvm/runtime/object.h>, - * the implementation is in <tvm/runtime/container/optional.h> to - * prevent circular includes. This additional include file is only - * required in compilation units that uses this method. - * - * \tparam ObjectRefType the target type, must be a subtype of ObjectRef - */ - template <typename ObjectRefType, - typename = std::enable_if_t<std::is_base_of_v<ObjectRef, ObjectRefType>>> - inline Optional<ObjectRefType> as() const; - - /*! \brief type indicate the container type. */ - using ContainerType = Object; - // Default type properties for the reference class. - static constexpr bool _type_is_nullable = true; + explicit ObjectRef(ObjectPtr<Object> data) : tvm::ffi::ObjectRef(data) {} protected: - /*! \brief Internal pointer that backs the reference. */ - ObjectPtr<Object> data_; /*! \return return a mutable internal ptr, can be used by sub-classes. */ Object* get_mutable() const { return data_.get(); } /*! @@ -622,7 +86,9 @@ class ObjectRef { * after we successfully moved the field. * \param ref The reference data. */ - static void FFIClearAfterMove(ObjectRef* ref) { ref->data_.data_ = nullptr; } + static void FFIClearAfterMove(ObjectRef* ref) { + details::ObjectUnsafe::LegacyClearObjectPtrAfterMove(ref); + } /*! * \brief Internal helper function get data_ as ObjectPtr of ObjectType. * \note only used for internal dev purpose. @@ -638,316 +104,11 @@ class ObjectRef { friend class TVMRetValue; friend class TVMArgsSetter; friend class ObjectInternal; - template <typename SubRef, typename BaseRef> - friend SubRef Downcast(BaseRef ref); -}; - -/*! - * \brief Get an object ptr type from a raw object ptr. - * - * \param ptr The object pointer - * \tparam BaseType The reference type - * \tparam ObjectType The object type - * \return The corresponding RefType - */ -template <typename BaseType, typename ObjectType> -inline ObjectPtr<BaseType> GetObjectPtr(ObjectType* ptr); - -/*! \brief ObjectRef hash functor */ -struct ObjectPtrHash { - size_t operator()(const ObjectRef& a) const { return operator()(a.data_); } - - template <typename T> - size_t operator()(const ObjectPtr<T>& a) const { - return std::hash<Object*>()(a.get()); - } }; -/*! \brief ObjectRef equal functor */ -struct ObjectPtrEqual { - bool operator()(const ObjectRef& a, const ObjectRef& b) const { return a.same_as(b); } - - template <typename T> - size_t operator()(const ObjectPtr<T>& a, const ObjectPtr<T>& b) const { - return a == b; - } -}; - -/*! - * \brief helper macro to declare a base object type that can be inherited. - * \param TypeName The name of the current type. - * \param ParentType The name of the ParentType - */ -#define TVM_DECLARE_BASE_OBJECT_INFO(TypeName, ParentType) \ - static_assert(!ParentType::_type_final, "ParentObj marked as final"); \ - static uint32_t RuntimeTypeIndex() { \ - 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."); \ - if (TypeName::_type_index != ::tvm::runtime::TypeIndex::kDynamic) { \ - return TypeName::_type_index; \ - } \ - return _GetOrAllocRuntimeTypeIndex(); \ - } \ - static uint32_t _GetOrAllocRuntimeTypeIndex() { \ - static uint32_t tindex = Object::GetOrAllocRuntimeTypeIndex( \ - TypeName::_type_key, TypeName::_type_index, ParentType::_GetOrAllocRuntimeTypeIndex(), \ - TypeName::_type_child_slots, TypeName::_type_child_slots_can_overflow); \ - return tindex; \ - } - -/*! - * \brief helper macro to declare type information in a final class. - * \param TypeName The name of the current type. - * \param ParentType The name of the ParentType - */ -#define TVM_DECLARE_FINAL_OBJECT_INFO(TypeName, ParentType) \ - static const constexpr bool _type_final = true; \ - static const constexpr int _type_child_slots = 0; \ - TVM_DECLARE_BASE_OBJECT_INFO(TypeName, ParentType) - -/*! \brief helper macro to suppress unused warning */ -#if defined(__GNUC__) -#define TVM_ATTRIBUTE_UNUSED __attribute__((unused)) -#else -#define TVM_ATTRIBUTE_UNUSED -#endif - -#define TVM_STR_CONCAT_(__x, __y) __x##__y -#define TVM_STR_CONCAT(__x, __y) TVM_STR_CONCAT_(__x, __y) - -#define TVM_OBJECT_REG_VAR_DEF static TVM_ATTRIBUTE_UNUSED uint32_t __make_Object_tid - -/*! - * \brief Helper macro to register the object type to runtime. - * Makes sure that the runtime type table is correctly populated. - * - * Use this macro in the cc file for each terminal class. - */ -#define TVM_REGISTER_OBJECT_TYPE(TypeName) \ - TVM_STR_CONCAT(TVM_OBJECT_REG_VAR_DEF, __COUNTER__) = TypeName::_GetOrAllocRuntimeTypeIndex() - -/* - * \brief Define the default copy/move constructor and assign operator - * \param TypeName The class typename. - */ -#define TVM_DEFINE_DEFAULT_COPY_MOVE_AND_ASSIGN(TypeName) \ - TypeName(const TypeName& other) = default; \ - TypeName(TypeName&& other) = default; \ - TypeName& operator=(const TypeName& other) = default; \ - TypeName& operator=(TypeName&& other) = default; - -/* - * \brief Define object reference methods. - * \param TypeName The object type name - * \param ParentType The parent type of the objectref - * \param ObjectName The type name of the object. - */ -#define TVM_DEFINE_OBJECT_REF_METHODS_WITHOUT_DEFAULT_CONSTRUCTOR(TypeName, ParentType, \ - ObjectName) \ - explicit TypeName(::tvm::runtime::ObjectPtr<::tvm::runtime::Object> n) : ParentType(n) {} \ - TVM_DEFINE_DEFAULT_COPY_MOVE_AND_ASSIGN(TypeName); \ - const ObjectName* operator->() const { return static_cast<const ObjectName*>(data_.get()); } \ - const ObjectName* get() const { return operator->(); } \ - using ContainerType = ObjectName; - -/* - * \brief Define object reference methods. - * \param TypeName The object type name - * \param ParentType The parent type of the objectref - * \param ObjectName The type name of the object. - */ -#define TVM_DEFINE_OBJECT_REF_METHODS(TypeName, ParentType, ObjectName) \ - TypeName() = default; \ - TVM_DEFINE_OBJECT_REF_METHODS_WITHOUT_DEFAULT_CONSTRUCTOR(TypeName, ParentType, ObjectName) - -/* - * \brief Define object reference methods that is not nullable. - * - * \param TypeName The object type name - * \param ParentType The parent type of the objectref - * \param ObjectName The type name of the object. - */ -#define TVM_DEFINE_NOTNULLABLE_OBJECT_REF_METHODS(TypeName, ParentType, ObjectName) \ - explicit TypeName(::tvm::runtime::ObjectPtr<::tvm::runtime::Object> n) : ParentType(n) {} \ - TVM_DEFINE_DEFAULT_COPY_MOVE_AND_ASSIGN(TypeName); \ - const ObjectName* operator->() const { return static_cast<const ObjectName*>(data_.get()); } \ - const ObjectName* get() const { return operator->(); } \ - static constexpr bool _type_is_nullable = false; \ - using ContainerType = ObjectName; - -/* - * \brief Define object reference methods of whose content is mutable. - * \param TypeName The object type name - * \param ParentType The parent type of the objectref - * \param ObjectName The type name of the object. - * \note We recommend making objects immutable when possible. - * This macro is only reserved for objects that stores runtime states. - */ -#define TVM_DEFINE_MUTABLE_OBJECT_REF_METHODS(TypeName, ParentType, ObjectName) \ - TypeName() = default; \ - TVM_DEFINE_DEFAULT_COPY_MOVE_AND_ASSIGN(TypeName); \ - explicit TypeName(::tvm::runtime::ObjectPtr<::tvm::runtime::Object> n) : ParentType(n) {} \ - ObjectName* operator->() const { return static_cast<ObjectName*>(data_.get()); } \ - using ContainerType = ObjectName; - -/* - * \brief Define object reference methods that is both not nullable and mutable. - * - * \param TypeName The object type name - * \param ParentType The parent type of the objectref - * \param ObjectName The type name of the object. - */ -#define TVM_DEFINE_MUTABLE_NOTNULLABLE_OBJECT_REF_METHODS(TypeName, ParentType, ObjectName) \ - explicit TypeName(::tvm::runtime::ObjectPtr<::tvm::runtime::Object> n) : ParentType(n) {} \ - TVM_DEFINE_DEFAULT_COPY_MOVE_AND_ASSIGN(TypeName); \ - ObjectName* operator->() const { return static_cast<ObjectName*>(data_.get()); } \ - ObjectName* get() const { return operator->(); } \ - static constexpr bool _type_is_nullable = false; \ - using ContainerType = ObjectName; - -/*! - * \brief Define CopyOnWrite function in an ObjectRef. - * \param ObjectName The Type of the Node. - * - * CopyOnWrite will generate a unique copy of the internal node. - * The node will be copied if it is referenced by multiple places. - * The function returns the raw pointer to the node to allow modification - * of the content. - * - * \code - * - * MyCOWObjectRef ref, ref2; - * ref2 = ref; - * ref.CopyOnWrite()->value = new_value; - * assert(ref2->value == old_value); - * assert(ref->value == new_value); - * - * \endcode - */ -#define TVM_DEFINE_OBJECT_REF_COW_METHOD(ObjectName) \ - static_assert(ObjectName::_type_final, \ - "TVM's CopyOnWrite may only be used for " \ - "Object types that are declared as final, " \ - "using the TVM_DECLARE_FINAL_OBJECT_INFO macro."); \ - ObjectName* CopyOnWrite() { \ - ICHECK(data_ != nullptr); \ - if (!data_.unique()) { \ - auto n = make_object<ObjectName>(*(operator->())); \ - ObjectPtr<Object>(std::move(n)).swap(data_); \ - } \ - return static_cast<ObjectName*>(data_.get()); \ - } - -// Implementations details below -// Object reference counting. -#if TVM_OBJECT_ATOMIC_REF_COUNTER - -inline void Object::IncRef() { ref_counter_.fetch_add(1, std::memory_order_relaxed); } - -inline void Object::DecRef() { - if (ref_counter_.fetch_sub(1, std::memory_order_release) == 1) { - std::atomic_thread_fence(std::memory_order_acquire); - if (this->deleter_ != nullptr) { - (*this->deleter_)(this); - } - } -} - -inline int Object::use_count() const { return ref_counter_.load(std::memory_order_relaxed); } - -#else - -inline void Object::IncRef() { ++ref_counter_; } - -inline void Object::DecRef() { - if (--ref_counter_ == 0) { - if (this->deleter_ != nullptr) { - (*this->deleter_)(this); - } - } -} - -inline int Object::use_count() const { return ref_counter_; } - -#endif // TVM_OBJECT_ATOMIC_REF_COUNTER - -template <typename TargetType> -inline bool Object::IsInstance() const { - const Object* self = this; - // NOTE: the following code can be optimized by - // compiler dead-code elimination for already known constants. - if (self != nullptr) { - // Everything is a subclass of object. - if (std::is_same<TargetType, Object>::value) return true; - if (TargetType::_type_final) { - // if the target type is a final type - // then we only need to check the equivalence. - return self->type_index_ == TargetType::RuntimeTypeIndex(); - } else { - // if target type is a non-leaf type - // Check if type index falls into the range of reserved slots. - uint32_t begin = TargetType::RuntimeTypeIndex(); - // The condition will be optimized by constant-folding. - if (TargetType::_type_child_slots != 0) { - uint32_t end = begin + TargetType::_type_child_slots; - if (self->type_index_ >= begin && self->type_index_ < end) return true; - } else { - if (self->type_index_ == begin) return true; - } - if (!TargetType::_type_child_slots_can_overflow) return false; - // Invariance: parent index is always smaller than the child. - if (self->type_index_ < TargetType::RuntimeTypeIndex()) return false; - // The rare slower-path, check type hierarchy. - return self->DerivedFrom(TargetType::RuntimeTypeIndex()); - } - } else { - return false; - } -} - -inline bool Object::unique() const { return use_count() == 1; } - -template <typename ObjectType, typename> -inline const ObjectType* ObjectRef::as() const { - if (data_ != nullptr && data_->IsInstance<ObjectType>()) { - return static_cast<ObjectType*>(data_.get()); - } else { - return nullptr; - } -} - -template <typename RefType, typename ObjType> -inline RefType GetRef(const ObjType* ptr) { - static_assert(std::is_base_of<typename RefType::ContainerType, ObjType>::value, - "Can only cast to the ref of same container type"); - if (!RefType::_type_is_nullable) { - ICHECK(ptr != nullptr); - } - return RefType(ObjectPtr<Object>(const_cast<Object*>(static_cast<const Object*>(ptr)))); -} - -template <typename BaseType, typename ObjType> -inline ObjectPtr<BaseType> GetObjectPtr(ObjType* ptr) { - static_assert(std::is_base_of<BaseType, ObjType>::value, - "Can only cast to the ref of same container type"); - return ObjectPtr<BaseType>(static_cast<Object*>(ptr)); -} - -template <typename SubRef, typename BaseRef> -inline SubRef Downcast(BaseRef ref) { - if (ref.defined()) { - ICHECK(ref->template IsInstance<typename SubRef::ContainerType>()) - << "Downcast from " << ref->GetTypeKey() << " to " << SubRef::ContainerType::_type_key - << " failed."; - } else { - ICHECK(SubRef::_type_is_nullable) << "Downcast from nullptr to not nullable reference of " - << SubRef::ContainerType::_type_key; - } - return SubRef(std::move(ref.data_)); -} +#define TVM_DECLARE_FINAL_OBJECT_INFO TVM_FFI_DECLARE_FINAL_OBJECT_INFO +#define TVM_DEFINE_NOTNULLABLE_OBJECT_REF_METHODS TVM_FFI_DEFINE_NOTNULLABLE_OBJECT_REF_METHODS } // namespace runtime } // namespace tvm - #endif // TVM_RUNTIME_OBJECT_H_ diff --git a/include/tvm/runtime/object.h b/include/tvm/runtime/object_backup.h similarity index 99% copy from include/tvm/runtime/object.h copy to include/tvm/runtime/object_backup.h index 527d663c02..ea31fcac48 100644 --- a/include/tvm/runtime/object.h +++ b/include/tvm/runtime/object_backup.h @@ -25,7 +25,6 @@ #include <tvm/runtime/c_runtime_api.h> #include <tvm/runtime/logging.h> -#include <tvm/ffi/object.h> #include <string> #include <type_traits> @@ -78,12 +77,11 @@ struct TypeIndex { /*! \brief runtime::RPCObjectRef */ kRuntimeRPCObjectRef = 9, // static assignments that may subject to change. - kStaticIndexEnd = 10, - /*! - * \brief Type index is allocated during runtime, keeping it as - * constant for now to ensure compatibility across versions - */ - kDynamic = 12 + kRuntimeClosure, + kRuntimeADT, + kStaticIndexEnd, + /*! \brief Type index is allocated during runtime. */ + kDynamic = kStaticIndexEnd }; }; // namespace TypeIndex diff --git a/src/runtime/debug_compile.cc b/src/runtime/debug_compile.cc new file mode 100644 index 0000000000..5f9f6b10d1 --- /dev/null +++ b/src/runtime/debug_compile.cc @@ -0,0 +1,35 @@ +/* + * 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/runtime/debug_compile.cc + * \brief File used for debug migration + */ +#include <tvm/runtime/container/string.h> + +namespace tvm { +namespace debug { + +String Test() { + String value = "xyz"; + return value; +} + +} +} \ No newline at end of file
