Skip to content

Conversation

@junrushao
Copy link
Member

@junrushao junrushao commented Sep 14, 2025

Depends on #32.

This PR introduces an experimental @c_class decorator that enables Python dataclass-like syntax for exposing C++ objects through TVM FFI. The decorator automatically handles field reflection, inheritance, and constructor generation for FFI-backed classes.

Example

On C++ side, register types using tvm::ffi::reflection::ObjectDef<>:

TVM_FFI_STATIC_INIT_BLOCK() {
    namespace refl = tvm::ffi::reflection;
    refl::ObjectDef<MyClass>()
        .def_static("__init__", [](int64_t v_i64, int32_t v_i32, double v_f64, float v_f32) -> Any {
            return ObjectRef(ffi::make_object<MyClass>(v_i64, v_i32, v_f64, v_f32));
        })
        .def_rw("v_i64", &MyClass::v_i64)
        .def_rw("v_i32", &MyClass::v_i32)
        .def_rw("v_f64", &MyClass::v_f64)
        .def_rw("v_f32", &MyClass::v_f32);
}

Mirror the same structure in Python using dataclass-style annotations:

from tvm_ffi.dataclasses import c_class, field

@c_class("example.MyClass")
class MyClass:
    v_i64: int
    v_i32: int
    v_f64: float = field(default=0.0)
    v_f32: float = field(default_factory=lambda: 1.0)

obj = MyClass(v_i64=4, v_i32=8)
obj.v_f64 = 3.14  # transparently forwards to the underlying C++ object

Future work

Supporting as many dataclass features as possible, including: repr, init, order, etc.

@junrushao junrushao force-pushed the 2025-09-14/c-cls branch 3 times, most recently from cd052b2 to c535491 Compare September 17, 2025 06:48
@junrushao junrushao marked this pull request as ready for review September 17, 2025 06:48
@junrushao junrushao changed the base branch from dev to main September 17, 2025 07:21
@junrushao junrushao requested a review from tqchen September 17, 2025 17:59
@junrushao junrushao force-pushed the 2025-09-14/c-cls branch 6 times, most recently from 858ec21 to 9fd39a4 Compare September 18, 2025 06:33
@junrushao junrushao changed the title feat: Introduce tvm_ffi.experimental.c_class feat: Introduce tvm_ffi.dataclasses.c_class Sep 18, 2025
@junrushao junrushao changed the title feat: Introduce tvm_ffi.dataclasses.c_class feat: Introduce Experimental tvm_ffi.dataclasses.c_class Sep 18, 2025
@junrushao junrushao force-pushed the 2025-09-14/c-cls branch 4 times, most recently from f8dfc67 to 5e336b0 Compare September 19, 2025 05:36
@junrushao junrushao force-pushed the 2025-09-14/c-cls branch 3 times, most recently from 3ff1f33 to 2e4f901 Compare September 19, 2025 07:08
junrushao added a commit that referenced this pull request Sep 19, 2025
Previously, `TypeInfo` stays strictly in C and is glued to Python via
Cython. This PR makes it Cython side registry to store Python objects,
i.e. `TypeInfo`, which makes it possible to lookup type info in pure
Python.

This PR is split from #8.
@junrushao junrushao force-pushed the 2025-09-14/c-cls branch 3 times, most recently from 78f3bd2 to 1d66b52 Compare September 19, 2025 18:21
@junrushao junrushao force-pushed the 2025-09-14/c-cls branch 2 times, most recently from 1c4f153 to 321a32f Compare September 19, 2025 19:49
@junrushao
Copy link
Member Author

@tqchen This PR is finally ready for review!

@junrushao junrushao requested a review from Copilot September 19, 2025 19:49
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces an experimental c_class decorator that enables Python dataclass-like syntax for exposing C++ objects through TVM FFI. The decorator automatically handles field reflection, inheritance, and constructor generation for FFI-backed classes.

  • Adds c_class decorator for creating dataclass-style FFI bindings
  • Implements field introspection and default value handling
  • Provides inheritance support for FFI classes

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
python/tvm_ffi/dataclasses/init.py Package initialization exporting the new dataclass functionality
python/tvm_ffi/dataclasses/c_class.py Core c_class decorator implementation with field reflection
python/tvm_ffi/dataclasses/field.py Field specification utilities similar to dataclasses.field
python/tvm_ffi/dataclasses/_utils.py Utility functions for class construction and method generation
python/tvm_ffi/core.pyi Type stub updates for the new dataclass_field attribute
python/tvm_ffi/cython/type_info.pxi Addition of dataclass_field to TypeField class
python/tvm_ffi/testing.py Example usage with test classes demonstrating inheritance
src/ffi/extra/testing.cc C++ test classes for validating the FFI dataclass functionality
tests/python/test_dataclasses_c_class.py Comprehensive tests for the new c_class decorator

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.


@dataclass(kw_only=True)
class Field:
"""(Experimental) Descriptor placeholder returned by :func:`tvm_ffi.dataclasses.field`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we only need to put experimental at the docstring for dataclasses __init__.py

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn’t hurt :))

@junrushao junrushao requested a review from tqchen September 20, 2025 07:19
@junrushao junrushao force-pushed the 2025-09-14/c-cls branch 4 times, most recently from 68590b0 to b2c1bc6 Compare September 20, 2025 21:48
@junrushao
Copy link
Member Author

@tqchen Rebased against the latest main. Could you re-review? Thanks!!

@tqchen tqchen merged commit e98b94e into apache:main Sep 22, 2025
6 checks passed
tqchen pushed a commit that referenced this pull request Sep 25, 2025
This PR addresses a memory corruption issue in Cython. The fix involves
ensuring that the `ByteArrayArg` object, which holds the type key, is
properly destructed after being passed to the `TVMFFITypeKeyToIndex`
function. This prevents a potential read-after-free scenario, as
reported by ASan.

## ASan Report

```
READ of size 9 at 0x604000420a30 thread T0
    ...
    #5 0x7fdb57299506 in __pyx_f_4core__type_info_create_from_type_key /home/dolores/Projects/tvm-ffi/build/core.cpp:17732
    ...

0x604000420a30 is located 32 bytes inside of 42-byte region [0x604000420a10,0x604000420a3a)
freed by thread T0 here:
    ...
    #4 0x7fdb572994e2 in __pyx_f_4core__type_info_create_from_type_key /home/dolores/Projects/tvm-ffi/build/core.cpp:17731
   ...

previously allocated by thread T0 here:
    ...
    #8 0x7fdb57299366 in __pyx_f_4core__type_info_create_from_type_key /home/dolores/Projects/tvm-ffi/build/core.cpp:17718
```

<img width="1444" height="904" alt="image"
src="https://github.com/user-attachments/assets/7a80d33d-dedf-41ca-ac77-108e63b8e57b"
/>

## Recommended ASan Options

One will need to preload `libasan` to properly work with CPython, and
`libstdc++` to properly intercept `__cxa_throw`. The path to those two
files can be found using:

```
ASAN="$(gcc -print-file-name=libasan.so)"
STDCXX="$(g++ -print-file-name=libstdc++.so.6)"
LD_PRELOAD="$ASAN $STDCXX"
```

Additionally, it might be helpful to tweak 

```
PYTHONMALLOC=malloc
```

and run with ASan options

```
ASAN_OPTIONS="detect_leaks=0:abort_on_error=1:symbolize=1:fast_unwind_on_malloc=0"
```

Notably, turning on `detect_leaks=1` will lead to bunch of irrelevant
noisy reports. Better turning it off.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants