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 f2e6f403 [CORE] Unify custom Any hash and equality hooks (#841)
f2e6f403 is described below

commit f2e6f403975e576dcf23080ad468f566a66bacc9
Author: Tianqi Chen <[email protected]>
AuthorDate: Sun Oct 11 13:57:16 2026 -0400

    [CORE] Unify custom Any hash and equality hooks (#841)
    
    Use the existing NativeFunction convention for custom Any hash and
    equality hooks, retaining packed Function support and strict int64/bool
    results. Keep custom dispatch inline with a direct native success path,
    preserve the packed fast path, and update native registrations and hook
    signatures.
---
 include/tvm/ffi/any.h                 | 36 +++++++++++++++++++++--------------
 include/tvm/ffi/reflection/accessor.h | 12 +++++++-----
 src/ffi/extra/reflection_extra.cc     |  7 +++++--
 tests/cpp/testing_object.h            |  8 ++++++--
 4 files changed, 40 insertions(+), 23 deletions(-)

diff --git a/include/tvm/ffi/any.h b/include/tvm/ffi/any.h
index 6226c749..6b65b8be 100644
--- a/include/tvm/ffi/any.h
+++ b/include/tvm/ffi/any.h
@@ -756,16 +756,20 @@ struct AnyHash {
    * \param src The source Any.
    * \return The hash value.
    */
-  static uint64_t CallCustomAnyHash(const TVMFFIAny& custom_any_hash, const 
Any& src) {
-    // NOTE: we explicitly use low-level ABI here since we do not want to have 
dep on function.h
-    // it also keeps the logic simple
+  TVM_FFI_INLINE static uint64_t CallCustomAnyHash(const TVMFFIAny& 
custom_any_hash,
+                                                   const Any& src) {
+    // Use the NativeFunction convention without depending on 
native_function.h.
     if (custom_any_hash.type_index == TypeIndex::kTVMFFIOpaquePtr) {
-      // we allow this attribute to be a function pointer for fast path
-      using FCustomAnyHashPtr = int64_t (*)(const Any&);
+      using FCustomAnyHashPtr = TVMFFIAny (*)(const Any&) noexcept;
       FCustomAnyHashPtr hash_func = 
reinterpret_cast<FCustomAnyHashPtr>(custom_any_hash.v_ptr);
       TVM_FFI_ICHECK_NOTNULL(hash_func);
-      return static_cast<uint64_t>(
-          (*hash_func)(src));  // NOLINT(clang-analyzer-core.CallAndMessage)
+      TVMFFIAny result = (*hash_func)(src);  // 
NOLINT(clang-analyzer-core.CallAndMessage)
+      if (TVM_FFI_PREDICT_TRUE(result.type_index == TypeIndex::kTVMFFIInt)) {
+        return static_cast<uint64_t>(result.v_int64);
+      }
+      Any error = details::AnyUnsafe::MoveTVMFFIAnyRawToAny(result);
+      TVM_FFI_ICHECK_EQ(error.type_index(), TypeIndex::kTVMFFIError);
+      throw details::AnyUnsafe::MoveFromAnyAfterCheck<Error>(std::move(error));
     } else {
       // alternatively it can be a ffi.Function object.
       TVM_FFI_ICHECK_EQ(custom_any_hash.type_index, 
TypeIndex::kTVMFFIFunction);
@@ -888,16 +892,20 @@ struct AnyEqual {
    * \param rhs The right-hand side Any.
    * \return The equality result.
    */
-  static bool CallCustomAnyEqual(const TVMFFIAny& custom_any_equal, const Any& 
lhs,
-                                 const Any& rhs) {
-    // NOTE: we explicitly use low-level ABI here since we do not want to have 
dep on function.h
-    // it also keeps the logic simple
+  TVM_FFI_INLINE static bool CallCustomAnyEqual(const TVMFFIAny& 
custom_any_equal, const Any& lhs,
+                                                const Any& rhs) {
+    // Use the NativeFunction convention without depending on 
native_function.h.
     if (custom_any_equal.type_index == TypeIndex::kTVMFFIOpaquePtr) {
-      // we allow this attribute to be a function pointer for fast path
-      using FCustomAnyEqualPtr = bool (*)(const Any&, const Any&);
+      using FCustomAnyEqualPtr = TVMFFIAny (*)(const Any&, const Any&) 
noexcept;
       FCustomAnyEqualPtr equal_func = 
reinterpret_cast<FCustomAnyEqualPtr>(custom_any_equal.v_ptr);
       TVM_FFI_ICHECK_NOTNULL(equal_func);
-      return (*equal_func)(lhs, rhs);  // 
NOLINT(clang-analyzer-core.CallAndMessage)
+      TVMFFIAny result = (*equal_func)(lhs, rhs);  // 
NOLINT(clang-analyzer-core.CallAndMessage)
+      if (TVM_FFI_PREDICT_TRUE(result.type_index == TypeIndex::kTVMFFIBool)) {
+        return result.v_int64 != 0;
+      }
+      Any error = details::AnyUnsafe::MoveTVMFFIAnyRawToAny(result);
+      TVM_FFI_ICHECK_EQ(error.type_index(), TypeIndex::kTVMFFIError);
+      throw details::AnyUnsafe::MoveFromAnyAfterCheck<Error>(std::move(error));
     } else {
       // alternatively it can be a ffi.Function object.
       TVM_FFI_ICHECK_EQ(custom_any_equal.type_index, 
TypeIndex::kTVMFFIFunction);
diff --git a/include/tvm/ffi/reflection/accessor.h 
b/include/tvm/ffi/reflection/accessor.h
index 08aa021b..18aa2f66 100644
--- a/include/tvm/ffi/reflection/accessor.h
+++ b/include/tvm/ffi/reflection/accessor.h
@@ -442,10 +442,10 @@ inline constexpr const char* kCompare = "__ffi_compare__";
  * hook operates at the ``Any`` level — it is called by ``AnyHash`` whenever
  * an ``Any`` holding an object of this type is used as a container key.
  *
- * Can be either a raw C function pointer (fast path, no boxing overhead) or
- * a ``Function`` object.
+ * Register a native hook with ``NativeFunction<int64_t(const 
Any&)>::FromNative<&Fn>()``
+ * or a packed ``Function`` object.
  *
- * Raw pointer signature: ``int64_t (*)(const Any& src)``
+ * Native adapter signature: ``TVMFFIAny (*)(const Any& src) noexcept``
  *
  * Function signature: ``(Any src) -> int64``
  */
@@ -456,9 +456,11 @@ inline constexpr const char* kAnyHash = "__any_hash__";
  * Unlike ``kEq`` (which operates on ``ObjectRef``), this hook operates at the
  * ``Any`` level — called by ``AnyEqual`` for container key comparison.
  *
- * Can be either a raw C function pointer (fast path) or a ``Function`` object.
+ * Register a native hook with
+ * ``NativeFunction<bool(const Any&, const Any&)>::FromNative<&Fn>()``
+ * or a packed ``Function`` object.
  *
- * Raw pointer signature: ``bool (*)(const Any& lhs, const Any& rhs)``
+ * Native adapter signature: ``TVMFFIAny (*)(const Any& lhs, const Any& rhs) 
noexcept``
  *
  * Function signature: ``(Any lhs, Any rhs) -> bool``
  */
diff --git a/src/ffi/extra/reflection_extra.cc 
b/src/ffi/extra/reflection_extra.cc
index 143bfe96..51efcd38 100644
--- a/src/ffi/extra/reflection_extra.cc
+++ b/src/ffi/extra/reflection_extra.cc
@@ -24,6 +24,7 @@
 #include <tvm/ffi/extra/structural_key.h>
 #include <tvm/ffi/reflection/access_path.h>
 #include <tvm/ffi/reflection/accessor.h>
+#include <tvm/ffi/reflection/native_function.h>
 #include <tvm/ffi/reflection/registry.h>
 
 #include <sstream>
@@ -206,8 +207,10 @@ inline void StructuralKeyRegisterReflection() {
       .def_ro("key", &StructuralKeyObj::key)
       .def_ro("hash_i64", &StructuralKeyObj::hash_i64);
   refl::TypeAttrDef<StructuralKeyObj>()
-      .attr(type_attr::kAnyHash, reinterpret_cast<void*>(&StructuralKeyHash))
-      .attr(type_attr::kAnyEqual, 
reinterpret_cast<void*>(&StructuralKeyEqual));
+      .attr(type_attr::kAnyHash,
+            NativeFunction<int64_t(const 
Any&)>::FromNative<&StructuralKeyHash>())
+      .attr(type_attr::kAnyEqual,
+            NativeFunction<bool(const Any&, const 
Any&)>::FromNative<&StructuralKeyEqual>());
 }
 
 TVM_FFI_STATIC_INIT_BLOCK() {
diff --git a/tests/cpp/testing_object.h b/tests/cpp/testing_object.h
index 3cd5474d..ad01c4a6 100644
--- a/tests/cpp/testing_object.h
+++ b/tests/cpp/testing_object.h
@@ -29,6 +29,7 @@
 #include <tvm/ffi/extra/structural_visit.h>
 #include <tvm/ffi/memory.h>
 #include <tvm/ffi/object.h>
+#include <tvm/ffi/reflection/native_function.h>
 #include <tvm/ffi/reflection/registry.h>
 #include <tvm/ffi/string.h>
 
@@ -99,8 +100,11 @@ inline void TIntObj::RegisterReflection() {
   refl::TypeAttrDef<TIntObj>()
       .def("test.GetValue", &TIntObj::GetValue)
       .attr("test.size", sizeof(TIntObj))
-      .attr(refl::type_attr::kAnyHash, 
reinterpret_cast<void*>(&TInt::CustomAnyHash))
-      .attr(refl::type_attr::kAnyEqual, 
reinterpret_cast<void*>(&TInt::CustomAnyEqual));
+      .attr(refl::type_attr::kAnyHash,
+            refl::NativeFunction<int64_t(const 
Any&)>::FromNative<&TInt::CustomAnyHash>())
+      .attr(
+          refl::type_attr::kAnyEqual,
+          refl::NativeFunction<bool(const Any&, const 
Any&)>::FromNative<&TInt::CustomAnyEqual>());
   // custom json serialization
   refl::TypeAttrDef<TIntObj>()
       .def(refl::type_attr::kDataToJson,

Reply via email to