gemini-code-assist[bot] commented on code in PR #508:
URL: https://github.com/apache/tvm-ffi/pull/508#discussion_r2971866468


##########
python/tvm_ffi/cython/type_info.pxi:
##########
@@ -996,6 +1014,64 @@ def _register_fields(type_info, fields):
     return type_fields
 
 
+cdef _register_py_methods(int32_t type_index, list py_methods):
+    """Register user-defined dunder methods as both TypeMethod and TypeAttr.
+
+    For each method in *py_methods*:
+    1. Convert the Python callable to a ``TVMFFIAny`` (``ffi::Function``).
+    2. Call ``TVMFFITypeRegisterMethod`` so the method appears in the
+       type's reflection metadata (``TypeInfo.methods``).
+    3. Ensure the type-attribute column exists (sentinel call with
+       ``type_index = kTVMFFINone``), then call ``TVMFFITypeRegisterAttr``
+       so the C++ runtime dispatch can find the hook.
+
+    Parameters
+    ----------
+    type_index : int
+        The runtime type index of the type.
+    py_methods : list[tuple[str, callable, bool]]
+        Each entry is ``(name, func, is_static)``.
+    """
+    cdef TVMFFIMethodInfo method_info
+    cdef TVMFFIAny func_any
+    cdef int c_api_ret_code
+    cdef ByteArrayArg name_arg
+    cdef TVMFFIAny sentinel_any
+
+    sentinel_any.type_index = kTVMFFINone
+    sentinel_any.v_int64 = 0
+
+    for name, func, is_static in py_methods:
+        name_bytes = c_str(name)
+        name_arg = ByteArrayArg(name_bytes)
+
+        # Convert Python callable -> TVMFFIAny (creates a FunctionObj)
+        func_any.type_index = kTVMFFINone
+        func_any.v_int64 = 0
+        TVMFFIPyPyObjectToFFIAny(
+            TVMFFIPyArgSetterFactory_,
+            <PyObject*>func,
+            &func_any,
+            &c_api_ret_code,
+        )
+        CHECK_CALL(c_api_ret_code)
+
+        # 1. Register as TypeMethod
+        method_info.name = name_arg.cdata
+        method_info.doc.data = NULL
+        method_info.doc.size = 0
+        method_info.flags = kTVMFFIFieldFlagBitMaskIsStaticMethod if is_static 
else 0
+        method_info.method = func_any
+        method_info.metadata.data = NULL
+        method_info.metadata.size = 0
+        CHECK_CALL(TVMFFITypeRegisterMethod(type_index, &method_info))
+
+        # 2. Ensure type-attr column exists (sentinel: kTVMFFINone)
+        CHECK_CALL(TVMFFITypeRegisterAttr(kTVMFFINone, &name_arg.cdata, 
&sentinel_any))
+        # 3. Register as TypeAttr
+        CHECK_CALL(TVMFFITypeRegisterAttr(type_index, &name_arg.cdata, 
&func_any))

Review Comment:
   ![high](https://www.gstatic.com/codereviewagent/high-priority.svg)
   
   The `func_any` variable, which holds an owned reference to a `FunctionObj`, 
is declared outside the loop and reused. This causes a reference leak in each 
iteration because the old object reference is overwritten without being 
decremented. To fix this, the `func_any` variable should be managed within the 
loop's scope, and its reference must be released after use. A `try...finally` 
block is a robust way to ensure the reference is always decremented, preventing 
memory leaks even if errors occur.
   
   ```
       cdef TVMFFIMethodInfo method_info
       cdef TVMFFIAny sentinel_any
   
       sentinel_any.type_index = kTVMFFINone
       sentinel_any.v_int64 = 0
   
       for name, func, is_static in py_methods:
           cdef TVMFFIAny func_any
           func_any.type_index = kTVMFFINone
           func_any.v_int64 = 0
           cdef int c_api_ret_code
   
           try:
               name_bytes = c_str(name)
               name_arg = ByteArrayArg(name_bytes)
   
               # Convert Python callable -> TVMFFIAny (creates a FunctionObj)
               TVMFFIPyPyObjectToFFIAny(
                   TVMFFIPyArgSetterFactory_,
                   <PyObject*>func,
                   &func_any,
                   &c_api_ret_code,
               )
               CHECK_CALL(c_api_ret_code)
   
               # 1. Register as TypeMethod
               method_info.name = name_arg.cdata
               method_info.doc.data = NULL
               method_info.doc.size = 0
               method_info.flags = kTVMFFIFieldFlagBitMaskIsStaticMethod if 
is_static else 0
               method_info.method = func_any
               method_info.metadata.data = NULL
               method_info.metadata.size = 0
               CHECK_CALL(TVMFFITypeRegisterMethod(type_index, &method_info))
   
               # 2. Ensure type-attr column exists (sentinel: kTVMFFINone)
               CHECK_CALL(TVMFFITypeRegisterAttr(kTVMFFINone, &name_arg.cdata, 
&sentinel_any))
               # 3. Register as TypeAttr
               CHECK_CALL(TVMFFITypeRegisterAttr(type_index, &name_arg.cdata, 
&func_any))
           finally:
               if func_any.type_index >= kTVMFFIStaticObjectBegin and 
func_any.v_obj != NULL:
                   TVMFFIObjectDecRef(<TVMFFIObjectHandle>func_any.v_obj)
   ```



##########
python/tvm_ffi/dataclasses/py_class.py:
##########
@@ -202,6 +202,31 @@ def _collect_own_fields(
     return fields
 
 
+def _collect_py_methods(cls: type) -> list[tuple[str, Any, bool]] | None:
+    """Extract recognized FFI dunder methods from the class body.
+
+    Only names listed in :data:`_FFI_RECOGNIZED_METHODS` are collected.
+
+    Returns a list of ``(name, func, is_static)`` tuples, or ``None``
+    if no eligible methods were found.
+    """
+    methods: list[tuple[str, Any, bool]] = []
+    for name in list(cls.__dict__):
+        if name not in _FFI_RECOGNIZED_METHODS:
+            continue
+        value = cls.__dict__[name]

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   To improve efficiency and readability, you can iterate directly over the 
dictionary's items using `cls.__dict__.items()`. This avoids creating a 
temporary list of keys and performing a second dictionary lookup for the value 
inside the loop.
   
   ```suggestion
       for name, value in cls.__dict__.items():
           if name not in _FFI_RECOGNIZED_METHODS:
               continue
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to