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


##########
docs/concepts/func_module.rst:
##########
@@ -0,0 +1,564 @@
+..  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.
+
+Function, Exception and Module
+==============================
+
+TVM-FFI provides a unified and ABI-stable calling convention that enables
+cross-language function calls between C++, Python, Rust, and other languages.
+Functions are first-class :doc:`TVM-FFI objects <object_and_class>`.
+
+This tutorial covers everything you need to know about defining, registering,
+and calling TVM-FFI functions, their exception handling, and working with 
modules.
+
+Glossary
+--------
+
+TVM-FFI ABI. :cpp:type:`TVMFFISafeCallType`
+  A stable C calling convention where every function is represented by a 
single signature,
+  which enables type-erased, cross-language function calls.
+  This calling convention is used across all TVM-FFI function calls at the ABI 
boundary.
+  See :ref:`Stable C ABI <tvm_ffi_c_abi>` for a quick introduction.
+
+TVM-FFI Function. :py:class:`tvm_ffi.Function`, 
:cpp:class:`tvm::ffi::FunctionObj`, :cpp:class:`tvm::ffi::Function`
+  A reference-counted function object and its managed reference, which wraps 
any callable,
+  including language-agnostic functions and lambdas (C++, Python, Rust, etc.),
+  member functions, external C symbols, and other callable objects,
+  all sharing the same calling convention.
+
+TVM-FFI Module. :py:class:`tvm_ffi.Module`, :cpp:class:`tvm::ffi::ModuleObj`, 
:cpp:class:`tvm::ffi::Module`
+  A namespace for a collection of functions, loaded from a shared library via 
``dlopen`` (Linux, macOS) or ``LoadLibraryW`` (Windows),
+  or statically linked to the current executable.
+
+Global Functions and Registry. :py:func:`tvm_ffi.get_global_func` and 
:py:func:`tvm_ffi.register_global_func`
+  A registry is a table that maps string names to 
:cpp:class:`~tvm::ffi::Function` objects
+  and their metadata (name, docs, signatures, etc.) for cross-language access.
+  Functions in the registry are called **global functions**.
+
+Common Usage
+------------
+
+TVM-FFI C Symbols
+~~~~~~~~~~~~~~~~~
+
+**Shared library**. Use :c:macro:`TVM_FFI_DLL_EXPORT_TYPED_FUNC` to export
+a function as a C symbol that follows the TVM-FFI ABI:
+
+.. code-block:: cpp
+
+   static int AddTwo(int x) { return x + 2; }
+
+   TVM_FFI_DLL_EXPORT_TYPED_FUNC(/*ExportName=*/add_two, /*Function=*/AddTwo)
+
+This creates a C symbol ``__tvm_ffi_<ExportName>`` in the shared library,
+which can then be loaded and called via :py:func:`tvm_ffi.load_module`:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   mod = tvm_ffi.load_module("path/to/library.so")
+   result = mod.add_two(40)  # -> 42
+
+**System library**. For symbols bundled in the same executable, use 
:cpp:func:`TVMFFIEnvModRegisterSystemLibSymbol`
+to register each symbol during static initialization within a 
:c:macro:`TVM_FFI_STATIC_INIT_BLOCK`.
+See :py:func:`tvm_ffi.system_lib` for a complete workflow.
+
+
+Global Functions
+~~~~~~~~~~~~~~~~
+
+**Register a global function**. In C++, use 
:cpp:class:`tvm::ffi::reflection::GlobalDef` to
+register a function:
+
+.. code-block:: cpp
+
+   #include <tvm/ffi/tvm_ffi.h>
+
+   static int AddOne(int x) { return x + 1; }
+
+   TVM_FFI_STATIC_INIT_BLOCK() {
+     namespace refl = tvm::ffi::reflection;
+     refl::GlobalDef()
+         .def("my_ext.add_one", AddOne, "Add one to the input");
+   }
+
+The :c:macro:`TVM_FFI_STATIC_INIT_BLOCK` macro ensures that registration occurs
+during library initialization. The registered function is then accessible from
+Python by the name ``my_ext.add_one``.
+
+In Python, use the decorator :py:func:`tvm_ffi.register_global_func` to 
register a global function:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   @tvm_ffi.register_global_func("my_ext.add_one")
+   def add_one(x: int) -> int:
+       return x + 1
+
+**Retrieve a global function**. After registration, functions are accessible 
by name.
+
+In Python, use :py:func:`tvm_ffi.get_global_func` to retrieve a global 
function:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   # Get a function from the global registry
+   add_one = tvm_ffi.get_global_func("my_ext.add_one")
+   result = add_one(41)  # -> 42
+
+In C++, use :cpp:func:`tvm::ffi::Function::GetGlobal` or 
:cpp:func:`tvm::ffi::Function::GetGlobalRequired`
+to retrieve a global function:
+
+.. code-block:: cpp
+
+   ffi::Function func = ffi::Function::GetGlobalRequired("my_ext.add_one");
+   int result = func(41)  // -> 42

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   This line in the C++ code example is missing a semicolon at the end. Without 
it, the code is syntactically incorrect and would not compile.
   
   ```suggestion
      int result = func(41);  // -> 42
   ```



##########
docs/concepts/func_module.rst:
##########
@@ -0,0 +1,564 @@
+..  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.
+
+Function, Exception and Module
+==============================
+
+TVM-FFI provides a unified and ABI-stable calling convention that enables
+cross-language function calls between C++, Python, Rust, and other languages.
+Functions are first-class :doc:`TVM-FFI objects <object_and_class>`.
+
+This tutorial covers everything you need to know about defining, registering,
+and calling TVM-FFI functions, their exception handling, and working with 
modules.
+
+Glossary
+--------
+
+TVM-FFI ABI. :cpp:type:`TVMFFISafeCallType`
+  A stable C calling convention where every function is represented by a 
single signature,
+  which enables type-erased, cross-language function calls.
+  This calling convention is used across all TVM-FFI function calls at the ABI 
boundary.
+  See :ref:`Stable C ABI <tvm_ffi_c_abi>` for a quick introduction.
+
+TVM-FFI Function. :py:class:`tvm_ffi.Function`, 
:cpp:class:`tvm::ffi::FunctionObj`, :cpp:class:`tvm::ffi::Function`
+  A reference-counted function object and its managed reference, which wraps 
any callable,
+  including language-agnostic functions and lambdas (C++, Python, Rust, etc.),
+  member functions, external C symbols, and other callable objects,
+  all sharing the same calling convention.
+
+TVM-FFI Module. :py:class:`tvm_ffi.Module`, :cpp:class:`tvm::ffi::ModuleObj`, 
:cpp:class:`tvm::ffi::Module`
+  A namespace for a collection of functions, loaded from a shared library via 
``dlopen`` (Linux, macOS) or ``LoadLibraryW`` (Windows),
+  or statically linked to the current executable.
+
+Global Functions and Registry. :py:func:`tvm_ffi.get_global_func` and 
:py:func:`tvm_ffi.register_global_func`
+  A registry is a table that maps string names to 
:cpp:class:`~tvm::ffi::Function` objects
+  and their metadata (name, docs, signatures, etc.) for cross-language access.
+  Functions in the registry are called **global functions**.
+
+Common Usage
+------------
+
+TVM-FFI C Symbols
+~~~~~~~~~~~~~~~~~
+
+**Shared library**. Use :c:macro:`TVM_FFI_DLL_EXPORT_TYPED_FUNC` to export
+a function as a C symbol that follows the TVM-FFI ABI:
+
+.. code-block:: cpp
+
+   static int AddTwo(int x) { return x + 2; }
+
+   TVM_FFI_DLL_EXPORT_TYPED_FUNC(/*ExportName=*/add_two, /*Function=*/AddTwo)
+
+This creates a C symbol ``__tvm_ffi_<ExportName>`` in the shared library,
+which can then be loaded and called via :py:func:`tvm_ffi.load_module`:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   mod = tvm_ffi.load_module("path/to/library.so")
+   result = mod.add_two(40)  # -> 42
+
+**System library**. For symbols bundled in the same executable, use 
:cpp:func:`TVMFFIEnvModRegisterSystemLibSymbol`
+to register each symbol during static initialization within a 
:c:macro:`TVM_FFI_STATIC_INIT_BLOCK`.
+See :py:func:`tvm_ffi.system_lib` for a complete workflow.
+
+
+Global Functions
+~~~~~~~~~~~~~~~~
+
+**Register a global function**. In C++, use 
:cpp:class:`tvm::ffi::reflection::GlobalDef` to
+register a function:
+
+.. code-block:: cpp
+
+   #include <tvm/ffi/tvm_ffi.h>
+
+   static int AddOne(int x) { return x + 1; }
+
+   TVM_FFI_STATIC_INIT_BLOCK() {
+     namespace refl = tvm::ffi::reflection;
+     refl::GlobalDef()
+         .def("my_ext.add_one", AddOne, "Add one to the input");
+   }
+
+The :c:macro:`TVM_FFI_STATIC_INIT_BLOCK` macro ensures that registration occurs
+during library initialization. The registered function is then accessible from
+Python by the name ``my_ext.add_one``.
+
+In Python, use the decorator :py:func:`tvm_ffi.register_global_func` to 
register a global function:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   @tvm_ffi.register_global_func("my_ext.add_one")
+   def add_one(x: int) -> int:
+       return x + 1
+
+**Retrieve a global function**. After registration, functions are accessible 
by name.
+
+In Python, use :py:func:`tvm_ffi.get_global_func` to retrieve a global 
function:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   # Get a function from the global registry
+   add_one = tvm_ffi.get_global_func("my_ext.add_one")
+   result = add_one(41)  # -> 42
+
+In C++, use :cpp:func:`tvm::ffi::Function::GetGlobal` or 
:cpp:func:`tvm::ffi::Function::GetGlobalRequired`
+to retrieve a global function:
+
+.. code-block:: cpp
+
+   ffi::Function func = ffi::Function::GetGlobalRequired("my_ext.add_one");
+   int result = func(41)  // -> 42
+
+
+Create Functions
+~~~~~~~~~~~~~~~~
+
+**From C++**. An :cpp:class:`tvm::ffi::Function` can be created via 
:cpp:func:`tvm::ffi::Function::FromTyped`
+or :cpp:class:`tvm::ffi::TypedFunction`'s constructor.
+
+.. code-block:: cpp
+
+   // Create type-erased function: add_type_erased
+   ffi::Function add_type_erased = ffi::Function::FromTyped([](int x, int y) {
+     return x + y;
+   });
+
+   // Create a typed function: add_typed
+   ffi::TypedFunction<int(int, int)> add_typed = [](int x, int y) {
+     return x + y;
+   };
+
+   // Convert a typed function to a type-erased function
+   ffi::Function generic = add_typed;
+
+**From Python**. Any Python :py:class:`Callable <collections.abc.Callable>` is 
automatically converted
+to a :py:class:`tvm_ffi.Function` at the ABI boundary. The example below 
demonstrates that in ``my_ext.bind``:
+
+- The input ``func`` is automatically converted to a 
:py:class:`tvm_ffi.Function`.
+- The returned lambda is also automatically converted to a 
:py:class:`tvm_ffi.Function`.
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   @tvm_ffi.register_global_func("my_ext.bind")
+   def bind(func, x):
+     assert isinstance(func, tvm_ffi.Function)
+     return lambda *args: func(x, *args)  # converted to `tvm_ffi.Function`
+
+   def add_x_y(x, y):
+     return x + y
+
+   func_bind = tvm_ffi.get_global_func("my_ext.bind")
+   add_y = func_bind(add_x_y, 1)  # bind x = 1
+   assert isinstance(add_y, tvm_ffi.Function)
+   print(add_y(2))  # -> 3
+
+
+:py:func:`tvm_ffi.convert` explicitly converts a Python callable to 
:py:class:`tvm_ffi.Function`:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   def add(x, y):
+     return x + y
+
+   func_add = tvm_ffi.convert(add)
+   print(func_add(1, 2))
+
+
+Exception ABI
+-------------
+
+This section describes the exception handling contract in the TVM-FFI Stable C 
ABI.
+Exceptions are first-class citizens in TVM-FFI, and this section specifies:
+
+- How to properly throw exceptions from a TVM-FFI ABI function
+- How to check for and propagate exceptions from a TVM-FFI ABI function
+
+TVM-FFI C ABI
+~~~~~~~~~~~~~
+
+All TVM-FFI functions ultimately conform to the :cpp:type:`TVMFFISafeCallType` 
signature,
+which provides a stable C ABI for cross-language calls. The C calling 
convention is defined as:
+
+.. code-block:: cpp
+
+   int tvm_ffi_c_abi(
+     void* handle,           // Resource handle
+     const TVMFFIAny* args,  // Input arguments (non-owning)
+     int32_t num_args,       // Number of input arguments
+     TVMFFIAny* result       // Output argument (owning, zero-initialized)
+   );
+
+**Input arguments**. The input arguments are passed as an array of 
:cpp:class:`tvm::ffi::AnyView` values,
+specified by ``args`` and ``num_args``.
+
+**Output argument**. The output argument ``result`` is an owning 
:cpp:type:`tvm::ffi::Any`
+that the caller must zero-initialize before the call.
+
+**Return value**. The ABI returns an **error code** that indicates:
+
+- ``0``: Success
+- ``-1``: Error occurred, retrievable with 
:cpp:func:`TVMFFIErrorMoveFromRaised`
+- ``-2``: Very rare frontend error
+
+.. hint::
+  See :doc:`Any <any>` for more details on the semantics of 
:cpp:type:`tvm::ffi::AnyView` and :cpp:type:`tvm::ffi::Any`.
+
+Retrieve Errors in C
+~~~~~~~~~~~~~~~~~~~~
+
+When a TVM-FFI function returns a non-zero code, it indicates that an error 
occurred
+and a :cpp:class:`tvm::ffi::ErrorObj` is stored in thread-local storage (TLS).
+This section shows how to retrieve the error object and print the error 
message and backtrace.
+
+.. note::
+
+  An :cpp:class:`~tvm::ffi::ErrorObj` is a :cpp:class:`~tvm::ffi::Object` with 
a :cpp:class:`TVMFFIErrorCell` payload
+  as defined below:
+
+  .. code-block:: cpp
+
+    typedef struct {
+      TVMFFIByteArray kind;       // Error type (e.g., "ValueError")
+      TVMFFIByteArray message;    // Error message
+      TVMFFIByteArray backtrace;  // Stack trace (most-recent call first)
+      void (*update_backtrace)(...);  // Hook to append/replace backtrace
+    } TVMFFIErrorCell;
+
+**Print an Error**. The example code below shows how to print an error message 
and backtrace.
+
+.. code-block:: cpp
+
+   #include <tvm/ffi/c_api.h>
+
+   void PrintError(TVMFFIObject* err) {
+     TVMFFIErrorCell* cell = (TVMFFIErrorCell*)((char*)err + 
sizeof(TVMFFIObject));
+     fprintf(stderr, "%.*s: %.*s\n", (int)cell->kind.size, cell->kind.data, 
(int)cell->message.size, cell->message.data);
+     if (cell->backtrace.size) {
+       fprintf(stderr, "Backtrace:\n%.*s\n", (int)cell->backtrace.size, 
cell->backtrace.data);
+     }
+   }
+
+The payload of the error object is a :cpp:type:`TVMFFIErrorCell` structure
+containing the error kind, message, and backtrace. It can be accessed
+by skipping the :cpp:type:`TVMFFIObject` header using pointer arithmetic.
+
+**Retrieve the error object**. When the error code is ``-1``, the error object 
is stored in TLS
+and can be retrieved with :cpp:func:`TVMFFIErrorMoveFromRaised`.
+
+.. code-block:: cpp
+
+   void HandleReturnCode(int rc) {
+     TVMFFIObject* err = NULL;
+     if (rc == 0) {
+       // Success
+     } else if (rc == -1) {
+       // Move the raised error from TLS (clears TLS slot)
+       TVMFFIErrorMoveFromRaised(&err); // now `err` owns the error object
+       if (err != NULL) {
+         PrintError(err); // print the error
+         TVMFFIObjectDecRef(err);  // Release the error object
+       }
+     } else if (rc == -2) {
+       // Frontend (e.g., Python) already has an exception set.
+       // Do not fetch from TLS; consult the frontend's error mechanism.
+     }
+   }
+
+This function transfers ownership of the error object to the caller and clears 
the TLS slot.
+You must call :cpp:func:`TVMFFIObjectDecRef` to release the object when done 
to avoid memory leaks.
+
+**Rare frontend errors**. Error code ``-2`` is reserved for rare frontend 
errors. It is returned only
+when the C API :cpp:func:`TVMFFIEnvCheckSignals` returns non-zero during 
execution, indicating that
+the Python side has a pending signal requiring attention. In this case, the 
caller should not fetch
+the error object from TLS but instead consult the frontend's error mechanism 
to handle the exception.
+
+Raise Errors in C
+~~~~~~~~~~~~~~~~~
+
+As part of TVM-FFI's calling convention, returning ``-1`` indicates that an 
error occurred
+and the error object is stored in the TLS slot. The error object can contain 
arbitrary
+user-defined information, such as error messages, backtraces, or Python 
frame-local variables.
+
+.. hint::
+  Compiler code generation may use similar patterns to raise errors in 
generated code.
+
+The example below sets the TLS error and returns ``-1`` using 
:cpp:func:`TVMFFIErrorSetRaisedFromCStr`:
+
+.. code-block:: cpp
+
+   #include <tvm/ffi/c_api.h>
+
+   int __tvm_ffi_my_kernel(void* handle, const TVMFFIAny* args,
+                           int32_t num_args, TVMFFIAny* result) {
+     // Validate inputs
+     if (num_args < 2) {
+       TVMFFIErrorSetRaisedFromCStr("ValueError", "Expected at least 2 
arguments");
+       return -1;
+     }
+     // ... kernel implementation ...
+     return 0;
+   }
+
+Alternatively, :cpp:func:`TVMFFIErrorSetRaisedFromCStrParts` accepts explicit 
string lengths,
+which is useful when the error kind and message are not null-terminated.
+
+**Propagating errors**. For chains of generated calls, simply propagate return 
codes—TLS carries
+the error details:
+
+.. code-block:: cpp
+
+   int outer_function(...) {
+     int err_code = 0;
+
+     err_code = inner_function(...);
+     if (err_code != 0) goto RAII;  // Propagate error; TLS has the details
+
+    RAII:

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   The indentation of the `RAII:` label is inconsistent with the surrounding 
code. For better readability and to maintain a consistent coding style, it 
should be aligned with the function's block scope.
   
   ```suggestion
      RAII:
   ```



##########
docs/concepts/func_module.rst:
##########
@@ -0,0 +1,564 @@
+..  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.
+
+Function, Exception and Module
+==============================
+
+TVM-FFI provides a unified and ABI-stable calling convention that enables
+cross-language function calls between C++, Python, Rust, and other languages.
+Functions are first-class :doc:`TVM-FFI objects <object_and_class>`.
+
+This tutorial covers everything you need to know about defining, registering,
+and calling TVM-FFI functions, their exception handling, and working with 
modules.
+
+Glossary
+--------
+
+TVM-FFI ABI. :cpp:type:`TVMFFISafeCallType`
+  A stable C calling convention where every function is represented by a 
single signature,
+  which enables type-erased, cross-language function calls.
+  This calling convention is used across all TVM-FFI function calls at the ABI 
boundary.
+  See :ref:`Stable C ABI <tvm_ffi_c_abi>` for a quick introduction.
+
+TVM-FFI Function. :py:class:`tvm_ffi.Function`, 
:cpp:class:`tvm::ffi::FunctionObj`, :cpp:class:`tvm::ffi::Function`
+  A reference-counted function object and its managed reference, which wraps 
any callable,
+  including language-agnostic functions and lambdas (C++, Python, Rust, etc.),
+  member functions, external C symbols, and other callable objects,
+  all sharing the same calling convention.
+
+TVM-FFI Module. :py:class:`tvm_ffi.Module`, :cpp:class:`tvm::ffi::ModuleObj`, 
:cpp:class:`tvm::ffi::Module`
+  A namespace for a collection of functions, loaded from a shared library via 
``dlopen`` (Linux, macOS) or ``LoadLibraryW`` (Windows),
+  or statically linked to the current executable.
+
+Global Functions and Registry. :py:func:`tvm_ffi.get_global_func` and 
:py:func:`tvm_ffi.register_global_func`
+  A registry is a table that maps string names to 
:cpp:class:`~tvm::ffi::Function` objects
+  and their metadata (name, docs, signatures, etc.) for cross-language access.
+  Functions in the registry are called **global functions**.
+
+Common Usage
+------------
+
+TVM-FFI C Symbols
+~~~~~~~~~~~~~~~~~
+
+**Shared library**. Use :c:macro:`TVM_FFI_DLL_EXPORT_TYPED_FUNC` to export
+a function as a C symbol that follows the TVM-FFI ABI:
+
+.. code-block:: cpp
+
+   static int AddTwo(int x) { return x + 2; }
+
+   TVM_FFI_DLL_EXPORT_TYPED_FUNC(/*ExportName=*/add_two, /*Function=*/AddTwo)
+
+This creates a C symbol ``__tvm_ffi_<ExportName>`` in the shared library,
+which can then be loaded and called via :py:func:`tvm_ffi.load_module`:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   mod = tvm_ffi.load_module("path/to/library.so")
+   result = mod.add_two(40)  # -> 42
+
+**System library**. For symbols bundled in the same executable, use 
:cpp:func:`TVMFFIEnvModRegisterSystemLibSymbol`
+to register each symbol during static initialization within a 
:c:macro:`TVM_FFI_STATIC_INIT_BLOCK`.
+See :py:func:`tvm_ffi.system_lib` for a complete workflow.
+
+
+Global Functions
+~~~~~~~~~~~~~~~~
+
+**Register a global function**. In C++, use 
:cpp:class:`tvm::ffi::reflection::GlobalDef` to
+register a function:
+
+.. code-block:: cpp
+
+   #include <tvm/ffi/tvm_ffi.h>
+
+   static int AddOne(int x) { return x + 1; }
+
+   TVM_FFI_STATIC_INIT_BLOCK() {
+     namespace refl = tvm::ffi::reflection;
+     refl::GlobalDef()
+         .def("my_ext.add_one", AddOne, "Add one to the input");
+   }
+
+The :c:macro:`TVM_FFI_STATIC_INIT_BLOCK` macro ensures that registration occurs
+during library initialization. The registered function is then accessible from
+Python by the name ``my_ext.add_one``.
+
+In Python, use the decorator :py:func:`tvm_ffi.register_global_func` to 
register a global function:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   @tvm_ffi.register_global_func("my_ext.add_one")
+   def add_one(x: int) -> int:
+       return x + 1
+
+**Retrieve a global function**. After registration, functions are accessible 
by name.
+
+In Python, use :py:func:`tvm_ffi.get_global_func` to retrieve a global 
function:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   # Get a function from the global registry
+   add_one = tvm_ffi.get_global_func("my_ext.add_one")
+   result = add_one(41)  # -> 42
+
+In C++, use :cpp:func:`tvm::ffi::Function::GetGlobal` or 
:cpp:func:`tvm::ffi::Function::GetGlobalRequired`
+to retrieve a global function:
+
+.. code-block:: cpp
+
+   ffi::Function func = ffi::Function::GetGlobalRequired("my_ext.add_one");
+   int result = func(41)  // -> 42
+
+
+Create Functions
+~~~~~~~~~~~~~~~~
+
+**From C++**. An :cpp:class:`tvm::ffi::Function` can be created via 
:cpp:func:`tvm::ffi::Function::FromTyped`
+or :cpp:class:`tvm::ffi::TypedFunction`'s constructor.
+
+.. code-block:: cpp
+
+   // Create type-erased function: add_type_erased
+   ffi::Function add_type_erased = ffi::Function::FromTyped([](int x, int y) {
+     return x + y;
+   });
+
+   // Create a typed function: add_typed
+   ffi::TypedFunction<int(int, int)> add_typed = [](int x, int y) {
+     return x + y;
+   };
+
+   // Convert a typed function to a type-erased function
+   ffi::Function generic = add_typed;
+
+**From Python**. Any Python :py:class:`Callable <collections.abc.Callable>` is 
automatically converted
+to a :py:class:`tvm_ffi.Function` at the ABI boundary. The example below 
demonstrates that in ``my_ext.bind``:
+
+- The input ``func`` is automatically converted to a 
:py:class:`tvm_ffi.Function`.
+- The returned lambda is also automatically converted to a 
:py:class:`tvm_ffi.Function`.
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   @tvm_ffi.register_global_func("my_ext.bind")
+   def bind(func, x):
+     assert isinstance(func, tvm_ffi.Function)
+     return lambda *args: func(x, *args)  # converted to `tvm_ffi.Function`
+
+   def add_x_y(x, y):
+     return x + y
+
+   func_bind = tvm_ffi.get_global_func("my_ext.bind")
+   add_y = func_bind(add_x_y, 1)  # bind x = 1
+   assert isinstance(add_y, tvm_ffi.Function)
+   print(add_y(2))  # -> 3
+
+
+:py:func:`tvm_ffi.convert` explicitly converts a Python callable to 
:py:class:`tvm_ffi.Function`:
+
+.. code-block:: python
+
+   import tvm_ffi
+
+   def add(x, y):
+     return x + y
+
+   func_add = tvm_ffi.convert(add)
+   print(func_add(1, 2))
+
+
+Exception ABI
+-------------
+
+This section describes the exception handling contract in the TVM-FFI Stable C 
ABI.
+Exceptions are first-class citizens in TVM-FFI, and this section specifies:
+
+- How to properly throw exceptions from a TVM-FFI ABI function
+- How to check for and propagate exceptions from a TVM-FFI ABI function
+
+TVM-FFI C ABI
+~~~~~~~~~~~~~
+
+All TVM-FFI functions ultimately conform to the :cpp:type:`TVMFFISafeCallType` 
signature,
+which provides a stable C ABI for cross-language calls. The C calling 
convention is defined as:
+
+.. code-block:: cpp
+
+   int tvm_ffi_c_abi(
+     void* handle,           // Resource handle
+     const TVMFFIAny* args,  // Input arguments (non-owning)
+     int32_t num_args,       // Number of input arguments
+     TVMFFIAny* result       // Output argument (owning, zero-initialized)
+   );
+
+**Input arguments**. The input arguments are passed as an array of 
:cpp:class:`tvm::ffi::AnyView` values,
+specified by ``args`` and ``num_args``.
+
+**Output argument**. The output argument ``result`` is an owning 
:cpp:type:`tvm::ffi::Any`
+that the caller must zero-initialize before the call.
+
+**Return value**. The ABI returns an **error code** that indicates:
+
+- ``0``: Success
+- ``-1``: Error occurred, retrievable with 
:cpp:func:`TVMFFIErrorMoveFromRaised`
+- ``-2``: Very rare frontend error
+
+.. hint::
+  See :doc:`Any <any>` for more details on the semantics of 
:cpp:type:`tvm::ffi::AnyView` and :cpp:type:`tvm::ffi::Any`.
+
+Retrieve Errors in C
+~~~~~~~~~~~~~~~~~~~~
+
+When a TVM-FFI function returns a non-zero code, it indicates that an error 
occurred
+and a :cpp:class:`tvm::ffi::ErrorObj` is stored in thread-local storage (TLS).
+This section shows how to retrieve the error object and print the error 
message and backtrace.
+
+.. note::
+
+  An :cpp:class:`~tvm::ffi::ErrorObj` is a :cpp:class:`~tvm::ffi::Object` with 
a :cpp:class:`TVMFFIErrorCell` payload
+  as defined below:
+
+  .. code-block:: cpp
+
+    typedef struct {
+      TVMFFIByteArray kind;       // Error type (e.g., "ValueError")
+      TVMFFIByteArray message;    // Error message
+      TVMFFIByteArray backtrace;  // Stack trace (most-recent call first)
+      void (*update_backtrace)(...);  // Hook to append/replace backtrace
+    } TVMFFIErrorCell;
+
+**Print an Error**. The example code below shows how to print an error message 
and backtrace.
+
+.. code-block:: cpp
+
+   #include <tvm/ffi/c_api.h>
+
+   void PrintError(TVMFFIObject* err) {
+     TVMFFIErrorCell* cell = (TVMFFIErrorCell*)((char*)err + 
sizeof(TVMFFIObject));
+     fprintf(stderr, "%.*s: %.*s\n", (int)cell->kind.size, cell->kind.data, 
(int)cell->message.size, cell->message.data);
+     if (cell->backtrace.size) {
+       fprintf(stderr, "Backtrace:\n%.*s\n", (int)cell->backtrace.size, 
cell->backtrace.data);
+     }
+   }
+
+The payload of the error object is a :cpp:type:`TVMFFIErrorCell` structure
+containing the error kind, message, and backtrace. It can be accessed
+by skipping the :cpp:type:`TVMFFIObject` header using pointer arithmetic.
+
+**Retrieve the error object**. When the error code is ``-1``, the error object 
is stored in TLS
+and can be retrieved with :cpp:func:`TVMFFIErrorMoveFromRaised`.
+
+.. code-block:: cpp
+
+   void HandleReturnCode(int rc) {
+     TVMFFIObject* err = NULL;
+     if (rc == 0) {
+       // Success
+     } else if (rc == -1) {
+       // Move the raised error from TLS (clears TLS slot)
+       TVMFFIErrorMoveFromRaised(&err); // now `err` owns the error object
+       if (err != NULL) {
+         PrintError(err); // print the error
+         TVMFFIObjectDecRef(err);  // Release the error object
+       }
+     } else if (rc == -2) {
+       // Frontend (e.g., Python) already has an exception set.
+       // Do not fetch from TLS; consult the frontend's error mechanism.
+     }
+   }
+
+This function transfers ownership of the error object to the caller and clears 
the TLS slot.
+You must call :cpp:func:`TVMFFIObjectDecRef` to release the object when done 
to avoid memory leaks.
+
+**Rare frontend errors**. Error code ``-2`` is reserved for rare frontend 
errors. It is returned only
+when the C API :cpp:func:`TVMFFIEnvCheckSignals` returns non-zero during 
execution, indicating that
+the Python side has a pending signal requiring attention. In this case, the 
caller should not fetch
+the error object from TLS but instead consult the frontend's error mechanism 
to handle the exception.
+
+Raise Errors in C
+~~~~~~~~~~~~~~~~~
+
+As part of TVM-FFI's calling convention, returning ``-1`` indicates that an 
error occurred
+and the error object is stored in the TLS slot. The error object can contain 
arbitrary
+user-defined information, such as error messages, backtraces, or Python 
frame-local variables.
+
+.. hint::
+  Compiler code generation may use similar patterns to raise errors in 
generated code.
+
+The example below sets the TLS error and returns ``-1`` using 
:cpp:func:`TVMFFIErrorSetRaisedFromCStr`:
+
+.. code-block:: cpp
+
+   #include <tvm/ffi/c_api.h>
+
+   int __tvm_ffi_my_kernel(void* handle, const TVMFFIAny* args,
+                           int32_t num_args, TVMFFIAny* result) {
+     // Validate inputs
+     if (num_args < 2) {
+       TVMFFIErrorSetRaisedFromCStr("ValueError", "Expected at least 2 
arguments");
+       return -1;
+     }
+     // ... kernel implementation ...
+     return 0;
+   }
+
+Alternatively, :cpp:func:`TVMFFIErrorSetRaisedFromCStrParts` accepts explicit 
string lengths,
+which is useful when the error kind and message are not null-terminated.
+
+**Propagating errors**. For chains of generated calls, simply propagate return 
codes—TLS carries
+the error details:
+
+.. code-block:: cpp
+
+   int outer_function(...) {
+     int err_code = 0;
+
+     err_code = inner_function(...);
+     if (err_code != 0) goto RAII;  // Propagate error; TLS has the details
+
+    RAII:
+     // clean up owned resources
+     return err_code;
+   }
+
+Function
+--------
+
+Layout and ABI
+~~~~~~~~~~~~~~
+
+:cpp:class:`tvm::ffi::FunctionObj` stores two call pointers in 
:cpp:class:`TVMFFIFunctionCell`:
+
+.. code-block:: cpp
+
+   typedef struct {
+     TVMFFISafeCallType safe_call;
+     void* cpp_call;
+   } TVMFFIFunctionCell;
+
+``safe_call`` is used for cross-ABI function calls: it intercepts exceptions 
and stores them in TLS.
+``cpp_call`` is used within the same DSO, where exceptions are thrown directly 
for better performance.
+
+.. important::
+
+  :cpp:func:`TVMFFIFunctionCall` is the idiomatic way to call a 
:cpp:class:`tvm::ffi::FunctionObj` in C,
+  while ``safe_call`` or ``cpp_call`` remain low-level ABIs for fast access.
+
+**Conversion with Any**. Since :py:class:`tvm_ffi.Function` is a TVM-FFI 
object, it follows the same
+conversion rules as any other TVM-FFI object. See :ref:`Object Conversion with 
Any <object-conversion-with-any>` for details.
+
+
+Throw and Catch Errors
+~~~~~~~~~~~~~~~~~~~~~~
+
+TVM-FFI gracefully handles exceptions across language boundaries without 
requiring manual
+error code management.
+
+.. important::
+  Stack traces from all languages are properly preserved and concatenated in 
the TVM-FFI Stable C ABI.
+
+**Python**. In Python, raise native :py:class:`Exception <Exception>` 
instances or derived classes.
+TVM-FFI catches these at the ABI boundary and converts them to 
:cpp:class:`tvm::ffi::Error` objects.
+When C++ code calls into Python and a Python exception occurs, it propagates 
back to C++ as a
+:cpp:class:`tvm::ffi::Error`, which C++ code can handle appropriately.
+
+**C++**. In C++, use :cpp:class:`tvm::ffi::Error` or the 
:c:macro:`TVM_FFI_THROW` macro:
+
+.. code-block:: cpp
+
+   #include <tvm/ffi/error.h>
+
+   void ThrowError(int x) {
+     if (x < 0) {
+       TVM_FFI_THROW(ValueError) << "x must be non-negative, got " << x;
+     }
+   }
+
+The :c:macro:`TVM_FFI_THROW` macro captures the current file name, line 
number, stack trace,
+and error message, then constructs a :cpp:class:`tvm::ffi::Error` object. At 
the ABI boundary,
+this error is stored in TLS and the function returns ``-1`` per the 
:cpp:type:`TVMFFISafeCallType`
+calling convention.
+
+.. hint::
+  A detailed implementation of such graceful handling behavior can be found
+  in :c:macro:`TVM_FFI_SAFE_CALL_BEGIN` / :c:macro:`TVM_FFI_SAFE_CALL_END` 
macros.
+
+
+C Registry APIs
+~~~~~~~~~~~~~~~
+
+.. list-table::
+   :header-rows: 1
+   :widths: 40 60
+
+   * - C API
+     - Description
+   * - :cpp:func:`TVMFFIFunctionGetGlobal`
+     - Get a function by name; returns an owning handle.
+   * - :cpp:func:`TVMFFIFunctionSetGlobal`
+     - Register a function in the global registry.
+   * - :cpp:func:`TVMFFIFunctionCall`
+     - Call a function with the given arguments.
+
+Compiler developers commonly need to look up global functions in generated 
code. Use
+:cpp:func:`TVMFFIFunctionGetGlobal` to retrieve a function by name, then call 
it with :cpp:func:`TVMFFIFunctionCall`.
+The example below demonstrates how to look up and call a global function in C:
+
+.. code-block:: cpp
+
+   int LookupAndCall(const char* global_function_name, const TVMFFIAny* args, 
int num_args, TVMFFIAny* result) {
+     TVMFFIObject* func = NULL;
+     int err_code;
+     if ((err_code = TVMFFIFunctionGetGlobal(global_function_name, &func)) != 
0)
+       goto RAII;
+     if ((err_code = TVMFFIFunctionCall(func, args, num_args, result)) != 0)
+       goto RAII;
+
+    RAII: // clean up owned resources

Review Comment:
   ![medium](https://www.gstatic.com/codereviewagent/medium-priority.svg)
   
   The indentation of the `RAII:` label is inconsistent with the surrounding 
code. For better readability and to maintain a consistent coding style, it 
should be aligned with the function's block scope.
   
   ```suggestion
      RAII: // clean up owned resources
   ```



-- 
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