This is an automated email from the ASF dual-hosted git repository.

tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git


The following commit(s) were added to refs/heads/main by this push:
     new e74e58f9 [FFI][PERF] Force-inline ObjectPtr wrapper special members 
(#761)
e74e58f9 is described below

commit e74e58f9d8a6fb1ece5722d0715f68187a8e0385
Author: Tianqi Chen <[email protected]>
AuthorDate: Mon Sep 7 17:24:05 2026 -0400

    [FFI][PERF] Force-inline ObjectPtr wrapper special members (#761)
    
    Force-inline all five special members of the single-payload wrappers
    that transitively own `ObjectPtr` storage.
    
    This keeps moved-from destructor cleanup within hot callers even after
    the compiler exhausts its ordinary inlining budget, while explicitly
    retaining noexcept move construction and assignment.
---
 include/tvm/ffi/container/variant.h | 10 ++++++----
 include/tvm/ffi/expected.h          | 27 +++++++++++++++++++++++++++
 include/tvm/ffi/object.h            | 32 ++++++++++++++++++--------------
 include/tvm/ffi/optional.h          | 32 ++++++++++++++++++++------------
 4 files changed, 71 insertions(+), 30 deletions(-)

diff --git a/include/tvm/ffi/container/variant.h 
b/include/tvm/ffi/container/variant.h
index 1823da42..494156d7 100644
--- a/include/tvm/ffi/container/variant.h
+++ b/include/tvm/ffi/container/variant.h
@@ -60,28 +60,30 @@ class Variant {
   template <typename T>
   using enable_if_variant_contains_t = std::enable_if_t<variant_contains_v<T>>;
   /// \endcond
+  // Special members are explicitly inlined to enable move cleanup 
optimizations
+  TVM_FFI_INLINE ~Variant() = default;
   /*!
    * \brief Constructor from another variant
    * \param other The other variant
    */
-  Variant(const Variant<V...>& other) = default;
+  TVM_FFI_INLINE Variant(const Variant<V...>& other) = default;
   /*!
    * \brief Constructor from another variant
    * \param other The other variant
    */
-  Variant(Variant<V...>&& other) noexcept = default;
+  TVM_FFI_INLINE Variant(Variant<V...>&& other) noexcept = default;
 
   /*!
    * \brief Assignment from another variant
    * \param other The other variant
    */
-  Variant& operator=(const Variant<V...>& other) = default;
+  TVM_FFI_INLINE Variant& operator=(const Variant<V...>& other) = default;
 
   /*!
    * \brief Assignment from another variant
    * \param other The other variant
    */
-  Variant& operator=(Variant<V...>&& other) noexcept = default;
+  TVM_FFI_INLINE Variant& operator=(Variant<V...>&& other) noexcept = default;
 
   /*!
    * \brief Constructor from a contained value
diff --git a/include/tvm/ffi/expected.h b/include/tvm/ffi/expected.h
index 6a7e3f2f..ffe91a25 100644
--- a/include/tvm/ffi/expected.h
+++ b/include/tvm/ffi/expected.h
@@ -43,6 +43,15 @@ class Unexpected {
                 "Unexpected<E> requires E to be Error or a subclass of 
Error.");
 
  public:
+  // Special members are explicitly inlined to enable move cleanup 
optimizations
+  TVM_FFI_INLINE ~Unexpected() = default;
+  /// \cond Doxygen_Suppress
+  TVM_FFI_INLINE Unexpected(const Unexpected&) = default;
+  TVM_FFI_INLINE Unexpected(Unexpected&&) noexcept = default;
+  /// \endcond
+  TVM_FFI_INLINE Unexpected& operator=(const Unexpected&) = default;
+  TVM_FFI_INLINE Unexpected& operator=(Unexpected&&) noexcept = default;
+
   /*! \brief Construct from an error value. */
   explicit Unexpected(E error) : error_(std::move(error)) {}
 
@@ -119,6 +128,15 @@ class Expected {
       "Expected with a cv-qualified void success type is not allowed. Use 
Expected<void>.");
   static_assert(!std::is_same_v<T, Error>, "Expected<Error> is not allowed. 
Use Error directly.");
 
+  // Special members are explicitly inlined to enable move cleanup 
optimizations
+  TVM_FFI_INLINE ~Expected() = default;
+  /// \cond Doxygen_Suppress
+  TVM_FFI_INLINE Expected(const Expected&) = default;
+  TVM_FFI_INLINE Expected(Expected&&) noexcept = default;
+  /// \endcond
+  TVM_FFI_INLINE Expected& operator=(const Expected&) = default;
+  TVM_FFI_INLINE Expected& operator=(Expected&&) noexcept = default;
+
   /*!
    * \brief Implicit constructor from a success value.
    * \param value The success value.
@@ -279,6 +297,15 @@ class Expected {
 template <>
 class Expected<void> {
  public:
+  // Special members are explicitly inlined to enable move cleanup 
optimizations
+  TVM_FFI_INLINE ~Expected() = default;
+  /// \cond Doxygen_Suppress
+  TVM_FFI_INLINE Expected(const Expected&) = default;
+  TVM_FFI_INLINE Expected(Expected&&) noexcept = default;
+  /// \endcond
+  TVM_FFI_INLINE Expected& operator=(const Expected&) = default;
+  TVM_FFI_INLINE Expected& operator=(Expected&&) noexcept = default;
+
   /*! \brief Construct a successful Expected<void>. */
   Expected() = default;
 
diff --git a/include/tvm/ffi/object.h b/include/tvm/ffi/object.h
index 5ca3c043..5c7832d3 100644
--- a/include/tvm/ffi/object.h
+++ b/include/tvm/ffi/object.h
@@ -416,8 +416,7 @@ class Object {
 template <typename T>
 class ObjectPtr {
  public:
-  // Core value members that perform ownership work are force-inlined so 
refcount paths do not
-  // depend on compiler cost models. Defaulted and empty members intentionally 
stay unmarked.
+  // Special members are explicitly inlined to enable move cleanup 
optimizations
   /*! \brief default constructor */
   ObjectPtr() = default;
   /*! \brief default constructor */
@@ -426,14 +425,14 @@ class ObjectPtr {
    * \brief copy constructor
    * \param other The value to be moved
    */
-  ObjectPtr(const ObjectPtr<T>& other)  // NOLINT(*)
+  TVM_FFI_INLINE 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(*)
+  TVM_FFI_INLINE ObjectPtr(const ObjectPtr<U>& other)  // NOLINT(*)
       : ObjectPtr(other.data_) {
     static_assert(std::is_base_of_v<T, U>, "can only assign of child class 
ObjectPtr to parent");
   }
@@ -441,7 +440,7 @@ class ObjectPtr {
    * \brief move constructor
    * \param other The value to be moved
    */
-  TVM_FFI_INLINE ObjectPtr(ObjectPtr<T>&& other)  // NOLINT(*)
+  TVM_FFI_INLINE ObjectPtr(ObjectPtr<T>&& other) noexcept  // NOLINT(*)
       : data_(other.data_) {
     other.data_ = nullptr;
   }
@@ -450,7 +449,7 @@ class ObjectPtr {
    * \param other The value to be moved
    */
   template <typename Y>
-  TVM_FFI_INLINE ObjectPtr(ObjectPtr<Y>&& other)  // NOLINT(*)
+  TVM_FFI_INLINE ObjectPtr(ObjectPtr<Y>&& other) noexcept  // NOLINT(*)
       : data_(other.data_) {
     static_assert(std::is_base_of_v<T, Y>, "can only assign of child class 
ObjectPtr to parent");
     other.data_ = nullptr;
@@ -483,7 +482,7 @@ class ObjectPtr {
    * \param other The value to be assigned.
    * \return reference to self.
    */
-  ObjectPtr<T>& operator=(const ObjectPtr<T>& other) {  // NOLINT(*)
+  TVM_FFI_INLINE 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(*)
@@ -494,7 +493,7 @@ class ObjectPtr {
    * \param other The value to be assigned.
    * \return reference to self.
    */
-  TVM_FFI_INLINE ObjectPtr<T>& operator=(ObjectPtr<T>&& other) {  // NOLINT(*)
+  TVM_FFI_INLINE ObjectPtr<T>& operator=(ObjectPtr<T>&& other) noexcept {  // 
NOLINT(*)
     // copy-and-swap idiom
     ObjectPtr(std::move(other)).swap(*this);  // NOLINT(*)
     return *this;
@@ -564,17 +563,20 @@ class Arc : public ObjectPtr<T> {
   Arc() = delete;
   Arc(std::nullptr_t) = delete;
 
+  // Special members are explicitly inlined to enable move cleanup 
optimizations
+  TVM_FFI_INLINE ~Arc() = default;
+
   /*! \brief Copy constructor. */
-  Arc(const Arc&) = default;
+  TVM_FFI_INLINE Arc(const Arc&) = default;
 
   /*! \brief Move constructor. */
-  Arc(Arc&&) = default;
+  TVM_FFI_INLINE Arc(Arc&&) noexcept = default;
 
   /*! \brief Copy assignment operator. */
-  Arc& operator=(const Arc&) = default;
+  TVM_FFI_INLINE Arc& operator=(const Arc&) = default;
 
   /*! \brief Move assignment operator. */
-  Arc& operator=(Arc&&) = default;
+  TVM_FFI_INLINE Arc& operator=(Arc&&) noexcept = default;
 
   /*!
    * \brief Copy-upcast an Arc of a derived Object type.
@@ -810,14 +812,16 @@ class ObjectRef {
  public:
   /*! \brief default constructor */
   ObjectRef() = default;
+  // Special members are explicitly inlined to enable move cleanup 
optimizations
+  TVM_FFI_INLINE ~ObjectRef() = default;
   /*! \brief copy constructor */
-  ObjectRef(const ObjectRef& other) = default;
+  TVM_FFI_INLINE ObjectRef(const ObjectRef& other) = default;
   /*! \brief move constructor */
   TVM_FFI_INLINE ObjectRef(ObjectRef&& other) noexcept : 
data_(std::move(other.data_)) {
     other.data_ = nullptr;
   }
   /*! \brief copy assignment */
-  ObjectRef& operator=(const ObjectRef& other) = default;
+  TVM_FFI_INLINE ObjectRef& operator=(const ObjectRef& other) = default;
   /*! \brief move assignment */
   TVM_FFI_INLINE ObjectRef& operator=(ObjectRef&& other) noexcept {
     data_ = std::move(other.data_);
diff --git a/include/tvm/ffi/optional.h b/include/tvm/ffi/optional.h
index 2b8dbd15..24ea229b 100644
--- a/include/tvm/ffi/optional.h
+++ b/include/tvm/ffi/optional.h
@@ -83,15 +83,17 @@ class Optional<T,
  public:
   // default constructors.
   Optional() = default;
+  // Special members are explicitly inlined to enable move cleanup 
optimizations
+  TVM_FFI_INLINE ~Optional() = default;
   // NOLINTBEGIN(google-explicit-constructor)
-  Optional(const Optional& other) = default;
-  Optional(Optional&& other) noexcept = default;
+  TVM_FFI_INLINE Optional(const Optional& other) = default;
+  TVM_FFI_INLINE Optional(Optional&& other) noexcept = default;
   TVM_FFI_INLINE Optional(std::optional<T> other) : data_(std::move(other)) {}
   Optional(std::nullopt_t) {}
   TVM_FFI_INLINE Optional(T other) : data_(std::move(other)) {}
   // NOLINTEND(google-explicit-constructor)
 
-  Optional& operator=(const Optional& other) = default;
+  TVM_FFI_INLINE Optional& operator=(const Optional& other) = default;
   TVM_FFI_INLINE Optional& operator=(Optional&& other) noexcept {
     data_ = std::move(other.data_);
     return *this;
@@ -180,13 +182,15 @@ class Optional<T,
  public:
   /*! \brief default constructor, represents nullopt (Any() is kTVMFFINone). */
   Optional() = default;
+  // Special members are explicitly inlined to enable move cleanup 
optimizations
+  TVM_FFI_INLINE ~Optional() = default;
   // NOLINTBEGIN(google-explicit-constructor)
   /*! \brief construct nullopt from std::nullopt. */
   Optional(std::nullopt_t) {}
   /*! \brief copy constructor. */
-  Optional(const Optional& other) = default;
+  TVM_FFI_INLINE Optional(const Optional& other) = default;
   /*! \brief move constructor. */
-  Optional(Optional&& other) noexcept = default;
+  TVM_FFI_INLINE Optional(Optional&& other) noexcept = default;
   /*! \brief construct from a value of type T (copy). */
   TVM_FFI_INLINE Optional(const T& value) : data_(value) {}
   /*! \brief construct from a value of type T (move). */
@@ -200,7 +204,7 @@ class Optional<T,
   // NOLINTEND(google-explicit-constructor)
 
   /*! \brief copy assignment. */
-  Optional& operator=(const Optional& other) = default;
+  TVM_FFI_INLINE Optional& operator=(const Optional& other) = default;
   /*! \brief move assignment. */
   TVM_FFI_INLINE Optional& operator=(Optional&& other) noexcept {
     data_ = std::move(other.data_);
@@ -375,9 +379,11 @@ class Optional<T, 
std::enable_if_t<use_object_ref_optional_v<T>>> : public Objec
   static constexpr bool _type_container_is_exact = T::_type_container_is_exact;
 
   Optional() = default;
+  // Special members are explicitly inlined to enable move cleanup 
optimizations
+  TVM_FFI_INLINE ~Optional() = default;
   // NOLINTBEGIN(google-explicit-constructor)
-  Optional(const Optional&) = default;
-  Optional(Optional&&) noexcept = default;
+  TVM_FFI_INLINE Optional(const Optional&) = default;
+  TVM_FFI_INLINE Optional(Optional&&) noexcept = default;
   explicit Optional(UnsafeInit tag) : ObjectRef(tag) {}
   Optional(std::nullopt_t) {}
   Optional(std::nullptr_t) {}
@@ -389,7 +395,7 @@ class Optional<T, 
std::enable_if_t<use_object_ref_optional_v<T>>> : public Objec
   TVM_FFI_INLINE Optional(T other) : ObjectRef(std::move(other)) {}
   // NOLINTEND(google-explicit-constructor)
 
-  Optional& operator=(const Optional&) = default;
+  TVM_FFI_INLINE Optional& operator=(const Optional&) = default;
   TVM_FFI_INLINE Optional& operator=(Optional&& other) noexcept {
     ObjectRef::operator=(std::move(other));
     return *this;
@@ -552,9 +558,11 @@ class Optional<T, std::enable_if_t<is_object_ptr_type_v<T> 
|| is_arc_type_v<T>>>
   using ContainerType = typename Traits::ContainerType;
 
   Optional() = default;
+  // Special members are explicitly inlined to enable move cleanup 
optimizations
+  TVM_FFI_INLINE ~Optional() = default;
   // NOLINTBEGIN(google-explicit-constructor)
-  Optional(const Optional&) = default;
-  Optional(Optional&&) noexcept = default;
+  TVM_FFI_INLINE Optional(const Optional&) = default;
+  TVM_FFI_INLINE Optional(Optional&&) noexcept = default;
   Optional(std::nullopt_t) : StorageType(nullptr) {}
   Optional(std::nullptr_t) : StorageType(nullptr) {}
   TVM_FFI_INLINE Optional(std::optional<T> other) {
@@ -565,7 +573,7 @@ class Optional<T, std::enable_if_t<is_object_ptr_type_v<T> 
|| is_arc_type_v<T>>>
   TVM_FFI_INLINE Optional(T value) : StorageType(std::move(value)) {}
   // NOLINTEND(google-explicit-constructor)
 
-  Optional& operator=(const Optional&) = default;
+  TVM_FFI_INLINE Optional& operator=(const Optional&) = default;
   TVM_FFI_INLINE Optional& operator=(Optional&& other) noexcept {
     static_cast<StorageType&>(*this) = 
std::move(static_cast<StorageType&>(other));
     return *this;

Reply via email to