)]}'
{
  "log": [
    {
      "commit": "62ba9b4a1d46be1f1fb8bc2e09a9be69e2d106a1",
      "tree": "a9d61ec6b8b41acff8687e1403f4a36921fa4aa3",
      "parents": [
        "329ec838400c18d364062f5ec75dbe4263461d37"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Mon Jul 13 00:49:26 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Jul 13 15:49:26 2026 +0800"
      },
      "message": "build(python)!: require CMake 3.26 for ABI-aware builds (#661)\n\nArchitecture:\n- Split Python interpreter discovery from development-component\ndiscovery so the extension ABI is known before CMake resolves link\ntargets.\n- Detect Py_GIL_DISABLED with the selected interpreter, pin its exact\nversion, and request only the development components used by that ABI\nbranch.\n- Set CMake 3.26 as the project minimum, matching the first release that\nprovides Development.SABIModule and python_add_library(USE_SABI).\n\nPublic Interfaces:\n- Standard CPython 3.12 and newer requires Development.Module and\nDevelopment.SABIModule and produces an abi3 extension.\n- Free-threaded CPython and CPython older than 3.12 require only\nDevelopment.Module and produce a version-specific extension with SOABI.\n- Building the root project now requires CMake 3.26 or newer. Runtime\nAPIs and the stable TVM FFI C ABI are unchanged.\n\nUI/UX:\n- none\n\nBehavioral Changes:\n- Stop requiring stable-ABI development artifacts for configurations\nthat cannot use the Limited API, including free-threaded CPython.\n- Preserve the existing abi3 path for standard CPython 3.12 and newer\nwhile allowing declared cp314t builds to configure against their native\nABI.\n- Fail early with an explicit CMake version requirement instead of\nreaching unsupported FindPython components or USE_SABI options on older\nCMake.\n\nDocs:\n- Raise the CMake prerequisite to 3.26 in the source-build guide,\nAGENTS.md, and the tracked developer-tool reference.\n\nTests:\n- Executed: staged pre-commit hooks, isolated CMake configuration for\nthe C++ project, and isolated CMake configuration with the Python module\nenabled.\n- Result: all executed checks passed.\n\nUntested Edge Cases:\n- Free-threaded CPython, Windows, and Python versions older than 3.12\nwere not available locally; their component selection remains covered by\nthe explicit CMake branches and should be exercised in CI.\n- Compilation, wheel creation, and the full unit-test suites were not\nrerun because this commit changes configuration and dependency selection\nonly.\n\nBREAKING CHANGE: Building TVM FFI now requires CMake 3.26 or newer.\nUpgrade CMake before configuring either the standalone C++ project or\nPython package."
    },
    {
      "commit": "329ec838400c18d364062f5ec75dbe4263461d37",
      "tree": "c52892868e8a34524fedb2418477949169ac083f",
      "parents": [
        "e245c0cf97daac78b3d4f231f5ff72e344c8d454"
      ],
      "author": {
        "name": "Yaxing Cai",
        "email": "caiyaxing666@gmail.com",
        "time": "Sat Jul 11 15:33:27 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Jul 11 15:33:27 2026 +0800"
      },
      "message": "[ORCJIT] Embed liborc_rt into the extension and add orc_rt selector (#660)\n\n## Motivation\n\nThe ORC runtime shipped as a separate `liborc_rt*.a` data file next to\nthe extension `.so` and was resolved at startup via a filesystem glob\n(through the `tvm_ffi_orcjit.DefaultOrcRuntimePath` Python hook). That\ncouples two artifacts, lets the runtime be lost/relocated by\nrepackaging, and does a filesystem glob to find its own runtime on first\nsession.\n\n## What this does\n\nBakes `liborc_rt.a` into the extension `.so`\u0027s `.rodata` via a generated\n`.incbin` stub (`orc_rt_embed.S.in`) and hands the bytes to\n`ExecutorNativePlatform` as a **zero-copy** `MemoryBuffer`. The wheel\nnow ships **one artifact**, startup does **no path lookup**, and the\nruntime cannot be separated from the extension. The embedded\n`start`/`end` symbols are `.hidden`, so they add no interposition\nsurface and don\u0027t affect the existing `--exclude-libs` symbol hiding.\n\nThis is **Solution A** of the embedded-orcrt design.\n\n### `default_session()`\n\nAlways uses the embedded runtime and is **deliberately not\nuser-configurable**: a shared process-wide singleton with a hidden\nruntime knob would let whichever caller runs first silently pick the\nplatform for everyone. The old `DefaultOrcRuntimePath` discovery hook is\ndropped.\n\n### User-created `ExecutionSession` — new `orc_rt` selector\n\nRenamed `orc_rt_path` → `orc_rt`, now a 4-state selector:\n\n| `orc_rt\u003d` | meaning |\n|---|---|\n| `\"auto\"` (default) | the embedded runtime |\n| `str` / `Path` | a custom `liborc_rt` archive on disk |\n| `bytes` | a custom `liborc_rt` archive in memory |\n| `None` | no ORC platform |\n\nC++ takes `Optional\u003cVariant\u003cString, Bytes\u003e\u003e`; empty `String` \u003d\u003d\n`\"auto\"`, `nullopt` \u003d\u003d `None`. Linux/ELF only, matching where the ORC\nplatform is wired up today; macOS/Windows ignore the selector as before.\nA custom runtime must match the LLVM/compiler-rt the extension was built\nagainst.\n\n## Testing\n\n- New `orc_rt` tests: custom path (str + `Path`), in-memory bytes,\n`None` (no platform), and bad-type rejection. Path/bytes cases are\n`@skipif` non-Linux (the selector only takes effect on ELF).\n- Verified locally (aarch64 Linux, LLVM 22): the `.so` carries the\nhidden `orc_rt_archive` symbols in `.rodata`, absent from the dynamic\ntable; no `liborc_rt*.a` bundled; C++ exception unwinding across a JIT\nframe works under `auto`/path/bytes (proving `ELFNixPlatform` is\ngenuinely installed).\n- Full addon suite: 164 passed, 11 skipped. clang-format / ruff /\ncmake-format / ASF-header all clean."
    },
    {
      "commit": "e245c0cf97daac78b3d4f231f5ff72e344c8d454",
      "tree": "1b5632e23e9372736ef7eb9a33e14189b6d5e0f3",
      "parents": [
        "f64ddbe6db5002aa737336696f67a91decdc7ed2"
      ],
      "author": {
        "name": "Yaxing Cai",
        "email": "caiyaxing666@gmail.com",
        "time": "Fri Jul 10 14:32:36 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 10 14:32:36 2026 +0800"
      },
      "message": "[ORCJIT] Add shared session and high-level load_module (#658)\n\nAdds a process-wide shared execution session and a unified `load_module`\non the `tvm_ffi_orcjit` addon, mirroring core `tvm_ffi.load_module`.\n\n## Changes\n\n- **`default_session()`** — leaked, process-wide shared\n`ExecutionSession`; settable ORC-runtime-path registry resolved on first\nuse.\n- **`ExecutionSession.load_module(objects, name)`** — loads one or more\nobjects (path `str`/`Path` or in-memory bytes; single item or list) into\none fresh JITDylib, injects context symbols eagerly, expands any\nembedded library binary into an import tree, and returns a plain\n`tvm_ffi.Module`.\n- **Recursive session lock** serializing all compound JITDylib ops\n(create / add / lookup+init / set-link-order / teardown) for safe\nshared-session use across threads; the resolved-call hot path stays\nlock-free.\n- **Namespace rename** — registered globals and the object key move to\n`ffi_orcjit`; `set_link_order` kept but dropped from the advertised\nsurface.\n- **`cpp.build`** — copy a single object through instead of `ld -r`,\nwhich some system linkers use to stamp a nonzero `sh_addr` on zero-size\nsections (e.g. `.note.GNU-stack`), producing a JITLink block that\noverlaps in `EHFrameEdgeFixer` and breaks C++ (eh_frame) loads.\n\nAlso folds in earlier addon cleanups (hide static-linked archive\nsymbols; numpydoc docstrings).\n\n## Testing\n\nNew `tests/test_session_load_module.py` covers input shapes, eager\ncontext, drop, embedded-binary expansion, and concurrent shared-session\nuse. Full addon suite green (154 passed, 3 skipped) on Linux aarch64."
    },
    {
      "commit": "f64ddbe6db5002aa737336696f67a91decdc7ed2",
      "tree": "93f1559522b4190e8a5f9c443d855185911203c6",
      "parents": [
        "5411a642d98bba14d4cb1e19a793c5b6758be019"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Jul 06 18:16:50 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Jul 06 18:16:50 2026 +0800"
      },
      "message": "[ORCJIT] Reinject contexts on first function lookup (#655)\n\n## Summary\n\n- defer context injection from empty-library construction to the first\nordinary function lookup\n- cache each successful refresh; after LLVM accepts an object,\nAddObjectFile publishes the refresh flag as false\n- keep AddObjectFile outside the thread-safety contract: it must not\nrace GetFunction, and a failed add naturally leaves the prior flag\nunchanged\n- keep concurrent GetFunction calls thread-safe with an acquire fast\npath and a mutex-protected, double-checked refresh on the false path,\nfollowed by one ordinary symbol lookup\n- preserve ordinary GetSymbol initializer execution and LLVM error\npropagation\n- keep the ORCJIT wheel test environment aligned with the\nrepository-wide parallel pytest configuration by installing pytest-xdist\n- bump the addon package to 0.1.1\n\nIf callers violate the AddObjectFile/GetFunction contract, LLVM may\nexpose a newly added symbol and GetFunction may return its stable\nallocated address before that object\u0027s context slots are refreshed. The\nsymbol remains visible, but context initialization is not guaranteed for\nthat unsupported overlap.\n\n## Regression\n\nOne C object defines only __tvm_ffi__library_ctx and a probe.\nBarrier-synchronized first lookups verify that every returned function\nobserves the injected pointer without adding another fixture.\n\n## Validation\n\n- GCC- and Clang-built addon suites: 139 passed, 3 platform skips each\n- fresh CI-equivalent wheel environment with local root package, default\nparallel pytest, and C/C++ quick starts\n- 200 rounds with eight concurrent first GetFunction callers after\nobject addition\n- focused context, invalid-object, constructor, and destructor tests\n- fresh 0.1.1 wheel build, isolated install, focused regression, and\nquick starts\n- applicable formatting and lint hooks"
    },
    {
      "commit": "5411a642d98bba14d4cb1e19a793c5b6758be019",
      "tree": "d95f21e1f0665c01d96ed0d86b293e329ac87e4c",
      "parents": [
        "520c201c258a612d96a2efb0d176e460919ccae1"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Jul 06 10:11:18 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Jul 05 22:11:18 2026 -0400"
      },
      "message": "[FFI] Back Optional and Variant by TVMFFIAny for a stable ABI layout (#657)\n\nThis PR makes `tvm::ffi::Optional\u003cT\u003e` and `tvm::ffi::Variant\u003c...\u003e`\nlayout stable across the contained type `T` by backing them with `Any`.\nNote that `Optional\u003cT\u003e` still falls back to `std::optional\u003cT\u003e` when `T`\ndoes not support Any storage.\n\nThis helps stabilize the future object-layout ABI of `Optional` and\n`Variant`."
    },
    {
      "commit": "520c201c258a612d96a2efb0d176e460919ccae1",
      "tree": "d907702b0997ad1b3674722f117864f4096e62ce",
      "parents": [
        "86c45a54ab72aa1d81b01ae86822fae4b959bd86"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Jul 05 23:57:32 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Jul 05 23:57:32 2026 +0800"
      },
      "message": "[FIX] Mark ObjectRef throw-only paths unreachable (#656)"
    },
    {
      "commit": "86c45a54ab72aa1d81b01ae86822fae4b959bd86",
      "tree": "b36553d20c8d3abddf636c3cf6c591b34b5753ad",
      "parents": [
        "95ea3a08fcee2f6103c4dd7d829f37abd3ae9b7e"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Jul 05 23:57:11 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Jul 05 23:57:11 2026 +0800"
      },
      "message": "[TEST] Run the Python test suite in parallel with a shared GPU lock (#654)"
    },
    {
      "commit": "95ea3a08fcee2f6103c4dd7d829f37abd3ae9b7e",
      "tree": "338e7b3a33e3165a89d12980175ec7f188f2127c",
      "parents": [
        "458aaf73b62285e5cd4481b9d197ac13b7c8cdb2"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Jul 05 08:19:13 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Jul 04 20:19:13 2026 -0400"
      },
      "message": "[FIX] Resolve JIT GPU backend by explicit signals, not stray /opt/rocm (#652)\n\nFixes #651.\n\nThe JIT extension backend selector decided CUDA-vs-HIP by probing for a\nROCm\nhome, whose fallback returns `/opt/rocm` whenever that directory merely\nexists.\nA CUDA/NVIDIA host carrying a stray `/opt/rocm` was therefore\nmisclassified as\nHIP even with `nvcc` present and no `hipcc`.\n\n`_detect_gpu_backend()` now resolves the backend from explicit signals,\nin\norder: the `TVM_FFI_GPU_BACKEND` override, then PyTorch build signals\n(`torch.version.hip` / `torch.version.cuda`), then an available `hipcc`\nwhen no\n`nvcc` is present. Detection defaults to CUDA when otherwise\ninconclusive, and\nthe existence of `/opt/rocm` alone never forces HIP. Toolkit-home,\ncompiler,\ninclude-path, flag, and architecture discovery are unchanged and run\nonly after\nthe backend is resolved, so CUDA and HIP state never mix."
    },
    {
      "commit": "458aaf73b62285e5cd4481b9d197ac13b7c8cdb2",
      "tree": "be289a5847934acc87bf99e1d9423fbfc02419fb",
      "parents": [
        "331664cd52342c53fbe4286072547184192cdfdf"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Sat Jul 04 11:55:45 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Jul 04 11:55:45 2026 -0400"
      },
      "message": "[FEAT][RUST]Add tvm_ffi::optional in Rust (#630)\n\nThis PR supports `ffi::optionalPod`, `ffi::optionalStr` in `Rust`. It\nkeeps the same memory layout as C++\u0027s ffi::optional.\n\n---------\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "331664cd52342c53fbe4286072547184192cdfdf",
      "tree": "da78d7ecfad378fa90c9d311a1d4523e23ea138a",
      "parents": [
        "28d09fe733a24fdf0b84249131dced8eee3e3574"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sat Jul 04 22:40:05 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Jul 04 10:40:05 2026 -0400"
      },
      "message": "[FIX] Make object construction exception-safe (#650)\n\nThis change makes SimpleObjAllocator strongly exception-safe when\nplacement construction throws.\n\nIt adds an allocator-local allocation guard to both ordinary object and\nvariable-sized array creation. The guard frees the matching aligned\nallocation during exception unwinding and is disarmed after successful\nconstruction. A focused object test verifies constructor exceptions\npropagate through make_object."
    },
    {
      "commit": "28d09fe733a24fdf0b84249131dced8eee3e3574",
      "tree": "9ed70b9287b0d48875063bc6855dea059725c7f0",
      "parents": [
        "230ae6c86ababb170baac6c485214e0a5af30702"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "yuchuan.7streams@gmail.com",
        "time": "Fri Jul 03 18:36:01 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jul 03 18:36:01 2026 -0400"
      },
      "message": "[FEAT][RUST]Add tvm_ffi::Map in Rust (#623)\n\nThis PR adds `tvm_ffi::Map` in Rust.\n\n`tvm_ffi::MapObj` in Rust and the `ffi::MapObj` in C++ share the same\nmemory layer at run time(when `TVM_FFI_DEBUG_WITH_ABI_CHANGE` is\n`False`). and `tvm_ffi::MapObj` will call the corresponding method of\n`ffi::Obj` in C++ through global function call directly in most cases.\n\n---------\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "230ae6c86ababb170baac6c485214e0a5af30702",
      "tree": "7f6f64d33b7a7c53c344149081c9ae89abeeadd6",
      "parents": [
        "84ee1a07f85645886d2eebc9ddd0ddf9488fd38a"
      ],
      "author": {
        "name": "Piotr Mazurek",
        "email": "piotr635@gmail.com",
        "time": "Mon Jun 29 17:39:03 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Jun 29 23:39:03 2026 +0800"
      },
      "message": "Include torch build/ABI in torch C-DLPack addon cache key (#644)\n\n## Problem\n\nThe prebuilt torch C-DLPack addon is cached under a filename derived\nonly from torch **major.minor** + a coarse device string:\n\n```python\nmajor, minor \u003d torch.__version__.split(\".\")[:2]\ndevice \u003d _torch_extension_device(torch)          # \"cuda\" / \"rocm\" / \"cpu\"\nlibname \u003d f\"libtorch_c_dlpack_addon_torch{major}{minor}-{device}{suffix}\"\nlib_path \u003d cache_dir / libname                   # cache_dir defaults to ~/.cache/tvm-ffi\nif not lib_path.exists():\n    ...build...                                  # otherwise reuse whatever is there\n```\n\nThis key omits:\n- the torch **patch** version (`2.9.0` vs `2.9.1`),\n- the build local-version tag carried in `torch.__version__` (`+cu121`\nvs `+cu124`, `+cpu`, …),\n- the C++ ABI flag (`torch._C._GLIBCXX_USE_CXX11_ABI`).\n\nSince the addon is a compiled extension linking libtorch\u0027s C++ ABI, two\ntorch installs that share `major.minor` + device but differ in patch /\nCUDA toolkit / ABI resolve to the **same** cached `.so`. The addon built\nagainst the first torch is then silently reused by the second — an ABI\nmismatch in the DLPack bridge that surfaces as crashes, memory faults,\nor **silently wrong tensor data**, not a clean error.\n\nThis is easy to hit whenever `~/.cache/tvm-ffi` is shared across\nenvironments — a shared/NFS home, or container images that mount the\nhost home and see the same cache under different torch builds.\n\n## Reproduce\n\n```bash\n# env A\npip install torch\u003d\u003d2.9.0+cu121 --index-url https://download.pytorch.org/whl/cu121\npython -c \"import tvm_ffi\"     # builds ~/.cache/tvm-ffi/libtorch_c_dlpack_addon_torch29-cuda.so\n\n# env B: same major.minor, different build/ABI, same cache dir\npip install torch\u003d\u003d2.9.1+cu124 --index-url https://download.pytorch.org/whl/cu124\npython -c \"import tvm_ffi\"     # REUSES the cu121-built torch29-cuda.so -\u003e ABI mismatch\n```\nThe same applies to any two builds that share\n`torch{major}{minor}-{device}`, including CPU and ROCm builds.\n\n## Fix\n\nFold the full torch build identity (`torch.__version__`, which already\ncarries patch + `+cuXXX`/`+rocmX.Y`/`+cpu`) and the C++ ABI flag into\nthe cached addon name via a short hash. Incompatible builds now get\ndistinct cache entries, while same-build reuse is unchanged. The build\nsubprocess receives `libname` from this call site, so it stays\nconsistent automatically.\n\nSigned-off-by: Piotr Mazurek \u003c27293258+tugot17@users.noreply.github.com\u003e\nCo-authored-by: Piotr Mazurek \u003c27293258+tugot17@users.noreply.github.com\u003e"
    },
    {
      "commit": "84ee1a07f85645886d2eebc9ddd0ddf9488fd38a",
      "tree": "9539333be882b1e7ab1d45874f849e5508e21426",
      "parents": [
        "1424286d49ab18784d3607030a79bcc644aabc86"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Jun 28 18:51:06 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Jun 28 18:51:06 2026 -0400"
      },
      "message": "[CORE] Add type subsumption and object-ref containment relations (#647)"
    },
    {
      "commit": "1424286d49ab18784d3607030a79bcc644aabc86",
      "tree": "722e28cdec7a58c333610b65bafaaf16b0b3e7ef",
      "parents": [
        "88e066ea2ed100da3c51e081fd4c036a33075fe4"
      ],
      "author": {
        "name": "pisarev",
        "email": "yuriy.pisareff@yandex.ru",
        "time": "Sun Jun 28 05:13:59 2026 +0300"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Jun 27 22:13:59 2026 -0400"
      },
      "message": "[FFI] Make StructuralEqual functor compare tensor content (#646)\n\nFixes #645.\n\nThe `StructuralEqual` functor calls `Equal(lhs, rhs, false,\n/*skip_tensor_content\u003d*/true)`, while the `StructuralHash` functor\nhashes content (`skip_tensor_content \u003d false`). The two are used\ntogether as the hash and key-equal of the constant de-duplication map in\nRelax VM codegen (`const_dedup_map_` in apache/tvm\n`src/relax/backend/vm/exec_builder.cc`). When hash and equal disagree,\nthe map invariant `equal(a, b) \u003d\u003e hash(a) \u003d\u003d hash(b)` does not hold, so\ntwo distinct constants of equal shape and dtype get merged on a bucket\ncollision and a later op reads the wrong constant.\n\nWhich pair collides depends on the STL bucket count, so the same model\nproduces wrong output under MSVC and correct output under libstdc++. The\ndefect is latent on every platform.\n\nThis change makes the functor compare content, so it agrees with the\nhash. Constants that are genuinely equal are still de-duplicated.\n\nVerified on a Windows build (MSVC 19.44, LLVM 18.1.8): after the change,\nYOLO11n det, YOLO11s cls, PP-OCRv5 det and PP-OCRv5 rec all match\nonnxruntime to within floating point; before, det and the PP-OCR models\nwere off by 6 to 61 percent relative error.\n\nFull analysis in #645."
    },
    {
      "commit": "88e066ea2ed100da3c51e081fd4c036a33075fe4",
      "tree": "e641f3d340898b6214085cda14891bb5341928cf",
      "parents": [
        "bb2e4586fff47ed75331b44639b1fb0ffb6f1e50"
      ],
      "author": {
        "name": "Yixin Dong",
        "email": "ubospica@gmail.com",
        "time": "Tue Jun 23 15:44:33 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jun 23 15:44:33 2026 -0400"
      },
      "message": "[PY] Support pickling FFI String and Bytes (#643)\n\n## Summary\n- Add pickle reductions for `tvm_ffi.core.String` and\n`tvm_ffi.core.Bytes` so only the Python payload is serialized.\n- Ensure unpickled values drop the hidden `_tvm_ffi_cached_object`\nbacking object.\n- Add regression coverage for cached FFI String/Bytes returned from\n`testing.echo`.\n\n## Notes\n- This is a clean branch based on the latest `apache/main` and\nsupersedes #642, which became dirty after main advanced.\n- `Bytes.__slots__` is intentionally unchanged because Python does not\nsupport non-empty `__slots__` on `bytes` subclasses.\n\n## Test plan\n- `uv pip install --reinstall --verbose . \u0026\u0026 .venv/bin/pytest -vvs\ntests/python/test_string.py`\n-\n`PYTHONPATH\u003d/raid/user_data/yixind/miniforge3/lib/python3.12/site-packages\npre-commit run --files python/tvm_ffi/cython/string.pxi\ntests/python/test_string.py`"
    },
    {
      "commit": "bb2e4586fff47ed75331b44639b1fb0ffb6f1e50",
      "tree": "e5161cff88f5f3c4611818b72932feee5ccb8a3b",
      "parents": [
        "fbb2b5c5f6e4f5f962db2ae74c9c1fc4c412843e"
      ],
      "author": {
        "name": "Yixin Dong",
        "email": "ubospica@gmail.com",
        "time": "Tue Jun 23 10:23:26 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jun 23 10:23:26 2026 -0400"
      },
      "message": "[PY] Distinguish FFI input and output annotations (#621)\n\n## Summary\n- Add separate input/output rendering APIs for `TypeSchema` so stubgen\ncan widen callable and constructor inputs without weakening returned or\nfield types.\n- Add a `__ffi_convert_type_schema__` TypeAttr hook for object\nconversions and wire `py_class`/`c_class` dataclass transform converter\nmetadata.\n- Generate `type_schema` metadata for Python-defined `@method`\nTypeMethods so reflection-driven stubgen can render their signatures.\n- Cover container asymmetry, object convert schema recursion, stubgen\nsignatures, partial type maps, `@method` metadata, and dataclass\nmetadata with regression tests.\n- Update the PR CI workflow to avoid Apache-disallowed third-party setup\nactions and run pre-commit without syncing the project during lint.\n\n## Validation\n- pre-commit hooks during commits, including ruff, ty, clang-format,\ncython-lint, CMake lint/format, and workflow YAML checks\n- `python -m pytest\ntests/python/test_stubgen.py::test_py_class_method_metadata_renders_stub_signature\ntests/python/test_typed_method.py -q`\n- `python -m pytest tests/python/test_stubgen.py -q`\n- `CUDA_VISIBLE_DEVICES\u003d\"\" python -m pytest tests/python -q` (`2322\npassed, 18 skipped, 2 xfailed`)\n- Manual output dumped under\n`tmp/2026-06-14-update-ffi/manual_check.out`\n- GitHub CI is green for lint, docs, Ubuntu, Ubuntu ARM, macOS, and\nWindows"
    },
    {
      "commit": "fbb2b5c5f6e4f5f962db2ae74c9c1fc4c412843e",
      "tree": "ad093a56045bda04da997ded4879f73276dd576b",
      "parents": [
        "78c4e430546a172d4d0058e0a7e38b35432cc529"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Jun 21 06:49:40 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Jun 21 06:49:40 2026 -0400"
      },
      "message": "[FFI] Add ref-qualified strict ObjectRef casts (#639)\n\nThis PR refactors strict ObjectRef casting to use the Any TypeTraits\nstrict-check path and adds strict throwing APIs.\n\nMain benefit:\n- `Any` and `ObjectRef` now have consistent strict `as` / `as_or_throw`\nAPIs: both rely on the same `TypeTraits` strict-check semantics, both\nreturn optional values for probe-style `as\u003cT\u003e()`, and both provide\nthrowing `as_or_throw\u003cT\u003e()` variants for required casts.\n- ObjectRef casts can now support richer compatibility checks through\n`TypeTraits\u003cObjectRefType\u003e::CheckAnyStrict`, instead of being limited to\nthe target ref\u0027s canonical `ContainerType` instance check.\n- `ObjectRefType::ContainerType` now has an explicit\n`_type_container_is_exact` invariant. Ordinary refs inherit `true` from\n`ObjectRef`, while richer parameterized refs such as `Array\u003cT\u003e`,\n`Map\u003cK,V\u003e`, `Tuple\u003c...\u003e`, and object-backed `Variant\u003c...\u003e` opt out\nbecause their accepted values are determined by `TypeTraits`, not only\nby the backing container. `GetRef` is guarded to only work for\nexact-container refs.\n\nAPI behavior:\n- `ObjectRef::as\u003cObjectRefType\u003e() const\u0026` returns\n`std::optional\u003cObjectRefType\u003e`. For a non-null source, it succeeds only\nwhen `TypeTraits\u003cObjectRefType\u003e::CheckAnyStrict` accepts the object\nthrough a compact temporary `TVMFFIAny` view. On success, it returns a\nref that shares the original object pointer. On type mismatch, it\nreturns `std::nullopt`.\n- `ObjectRef::as\u003cObjectRefType\u003e() \u0026\u0026` has the same strict-check and\n`std::nullopt` behavior, but moves the object pointer into the returned\nref on success and clears the source ref.\n- For null `ObjectRef` sources, `ObjectRef::as\u003cObjectRefType\u003e()` returns\na successful null ref when the target ref type is nullable, and returns\n`std::nullopt` for non-nullable target refs. The null path is explicit\nand is not treated as a globally cold failure path.\n- `ObjectRef::as_or_throw\u003cObjectRefType\u003e() const\u0026` and `\u0026\u0026` are the\nthrowing forms of the same strict ObjectRef cast. They return\n`ObjectRefType` on success, preserve/move the object pointer according\nto the receiver qualifier, return a null ref for nullable null targets,\nand throw `TypeError` for non-nullable null or type-mismatch cases.\n- `Any::as_or_throw\u003cT\u003e() const\u0026` and `\u0026\u0026` are strict reinterpretation\nhelpers for `Any`. They call the corresponding strict `as\u003cT\u003e()` path,\nreturn `T` on success, and throw `TypeError` on mismatch. They do not\nrun fallback conversions; use `cast\u003cT\u003e()` when conversion is intended.\n- Optional-returning `as` APIs intentionally do not use success/failure\nprediction annotations because `std::nullopt` can be a normal probe\nresult. Throwing APIs mark only the final failure/throw path as cold,\nand `ObjectRef::as_or_throw` marks the strict-check success path as\nlikely because mismatch throws.\n\nImplementation notes:\n- `ObjectRef::as\u003cT\u003e()` no longer relies on `T::ContainerType` as the\ncomplete runtime compatibility test. It piggy-backs on Any `TypeTraits`\nstrict checks, so ref types with richer strict compatibility rules work\nconsistently with `Any`.\n- The temporary `TVMFFIAny` setup is deliberately kept inline in the\nnon-null ObjectRef paths. This preserves explicit null behavior and lets\n`as_or_throw` call `TypeTraits\u003cT\u003e::GetMismatchTypeInfo` for richer\ndiagnostics instead of reducing to `as\u003cT\u003e()` and losing the synthesized\nAny view.\n- The compact temporary Any view is expected to optimize away on hot\npaths; GCC/Clang assembly probes confirmed direct object-header\nloads/type-index comparisons for the checked ObjectRef paths.\n\nChanges:\n- Add ref-qualified `ObjectRef::as\u003cT\u003e()` and\n`ObjectRef::as_or_throw\u003cT\u003e()` overloads for const and rvalue receivers.\n- Add `Any::as_or_throw\u003cT\u003e()` const/rvalue helpers.\n- Keep ObjectRef null handling explicit while using temporary\n`TVMFFIAny` views for rich `TypeTraits` checks and mismatch messages.\n- Add `_type_container_is_exact` and guard `GetRef` so it is only used\nfor refs whose `ContainerType` is an exact acceptance predicate.\n- Add focused tests for const and move variants of `as\u003cT\u003e()` and\n`as_or_throw\u003cT\u003e()`, plus compile-time coverage for exact/non-exact\ncontainer-ref flags.\n- Update `TVM_FFI_UNSAFE_ASSUME` lowering to be more robust for GCC."
    },
    {
      "commit": "78c4e430546a172d4d0058e0a7e38b35432cc529",
      "tree": "6fb181b86c3da3c21e63f504e3c1fcc42090d3af",
      "parents": [
        "e8a5516fa1e0e02d087d4efd7e6e9ba2244cf28a"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Jun 21 06:38:51 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Jun 21 06:38:51 2026 -0400"
      },
      "message": "[API] Add type index query mode (#640)\n\n## Summary\n- Add query-only behavior to TVMFFITypeGetOrAllocIndex when\nparent_type_index \u003d\u003d -2.\n- Return the existing registered type index on hit, or -2 on miss\nwithout allocating/registering or mutating parent metadata.\n- Document the concrete -2 C API behavior and add focused C++ coverage\nfor hit and miss/no-registration behavior.\n\nThis query mode is reserved for a future release update that may\noptionally query type indices at startup.\n\n## Validation\n- ./build/cpp_tests/lib/tvm_ffi_tests\n--gtest_filter\u003dObject.TypeGetOrAllocIndexQuery*\n- ctest -V -C RelWithDebugInfo --test-dir build/cpp_tests\n--output-on-failure\n- pre-commit run --files include/tvm/ffi/c_api.h src/ffi/object.cc\ntests/cpp/test_object.cc"
    },
    {
      "commit": "e8a5516fa1e0e02d087d4efd7e6e9ba2244cf28a",
      "tree": "b5b53ea79ca33911ad7d62730e0af7473b0e29d1",
      "parents": [
        "102fe0e93a9627720f3f190d6efc7450c74604a7"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Fri Jun 19 21:58:39 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jun 19 21:58:39 2026 -0400"
      },
      "message": "[CORE] Invert object/type_traits dependency layering (#638)\n\n## Summary\n- invert the header dependency so `object.h` includes `type_traits.h`,\nand move shared type metadata/helpers like `StaticTypeKey`,\n`TypeIndexToTypeKey`, and `details::type_contains_v` into\n`type_traits.h`\n- move object and `Optional` trait specializations into their owning\nheaders, move `DLTensor*` traits into `tensor.h`, and keep the\n`uint64_t` overflow-checked specialization near the end of `any.h`\n- add a narrow ASF header checker skip for `.agents/skills/**/SKILL.md`\nso skill files can keep frontmatter at byte 0"
    },
    {
      "commit": "102fe0e93a9627720f3f190d6efc7450c74604a7",
      "tree": "c75f4ab7da058a40157575214a756a09bf82617e",
      "parents": [
        "98440793acb46f35c7611315df2e187195249605"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Thu Jun 18 21:48:58 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jun 18 21:48:58 2026 -0400"
      },
      "message": "[OBJECT] Make object info macro compatible with CRTP (#636)\n\nThis PR makes `TVM_FFI_DECLARE_OBJECT_INFO_PREDEFINED_TYPE_KEY`\ncompatible with CRTP-style object declarations, and fixes the MSVC build\nfailure seen with that pattern.\n\nWhen the macro is expanded inside a CRTP base template, the cached\n`_type_index` member is declared in the current CRTP base\nspecialization. The `_type_index` initializer now calls\n`_GetOrAllocRuntimeTypeIndex()` through current-class lookup instead of\nqualifying that function through the CRTP leaf type, which avoids MSVC\nlookup failures on incomplete CRTP leaf types.\n\nOther `TypeName::` lookups are preserved so leaf-provided metadata such\nas `_type_key` and child-slot overrides continue to be used.\n\nA generic `CRTPObject\u003cT\u003e` / `LeafObject` regression test is added in\n`test_object.cc`.\n\nValidation:\n- `cmake -S . -B build-crtp -G Ninja -DCMAKE_BUILD_TYPE\u003dRelease\n-DTVM_FFI_USE_EXTRA_CXX_API\u003dON -DTVM_FFI_BUILD_TESTS\u003dON`\n- `ninja -C build-crtp tvm_ffi_tests`\n- `./build-crtp/lib/tvm_ffi_tests\n--gtest_filter\u003dObject.CRTPObjectInfo:Object.TypeInfo`\n- `./build-crtp/lib/tvm_ffi_tests --gtest_filter\u003dObject.*`\n- `pre-commit run --files include/tvm/ffi/object.h\ntests/cpp/test_object.cc`"
    },
    {
      "commit": "98440793acb46f35c7611315df2e187195249605",
      "tree": "f13eae2b3052f55528236a8d10ee472eea3fd9ac",
      "parents": [
        "c4e07180c9c52b9c72a5a0e5be3c2a3b2326b9c8"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Thu Jun 18 15:48:03 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jun 18 15:48:03 2026 -0400"
      },
      "message": "[OBJECT] Optimize dynamic RuntimeTypeIndex loads (#634)\n\nThis PR caches dynamically allocated object type indices in a static\ninline const `_type_index` and makes `RuntimeTypeIndex` return the\ncached value directly. `_GetOrAllocRuntimeTypeIndex` is marked cold and\nmoves to cold/startup code, reducing the hot accessor to a plain load.\n\nSide codegen probe for a dynamic object accessor:\n\n- `ReadDynTypeIndex`: 176 B -\u003e 14 B\n- total probe object: 769 B -\u003e 634 B\n- hot path no longer contains function-local static guard/allocation\nchecks\n- added static inline storage cost is explicit: 4 B `_type_index`, 8 B\nguard, 8 B `.init_array`, plus small startup init"
    },
    {
      "commit": "c4e07180c9c52b9c72a5a0e5be3c2a3b2326b9c8",
      "tree": "85dd8cfd4f233c449c81122b97ec995497ed74d5",
      "parents": [
        "fcd5ab4f5bd35ed3f36e547f34f7330534fe99dc"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Thu Jun 18 15:33:19 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jun 18 15:33:19 2026 -0400"
      },
      "message": "[CI] Ignore existing DLLs in Windows wheel repair (#635)\n\nWindows wheel repair started failing under the current\ncibuildwheel/delvewheel stack with:\n\n```text\nFileNotFoundError: Unable to find library: tvm_ffi_testing.dll\n```\n\n`tvm_ffi_testing.dll` is already shipped inside the wheel under\n`tvm_ffi/lib/`. Configure the Windows repair command to pass\n`--ignore-existing`, so delvewheel does not try to rediscover DLLs that\nare already bundled in the wheel while repairing `tvm_ffi/core*.pyd`.\n\nValidation:\n\n- Manually triggered Windows wheel workflow on `tqchen/tvm-ffi:main`\npassed with this change.\n- `pre-commit run --all-files` passed locally."
    },
    {
      "commit": "fcd5ab4f5bd35ed3f36e547f34f7330534fe99dc",
      "tree": "d15f61f195189fdd9a7139f530f274ed499acdf5",
      "parents": [
        "fc275d6f4de391e0d51f2097cc601d56a5d88bd3"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Thu Jun 18 14:04:41 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jun 18 14:04:41 2026 -0400"
      },
      "message": "[CI] Phase out Python 3.8 wheel builds (#633)\n\ncibuildwheel 4.x no longer accepts Python 3.8 build selectors, so the\nwheel build configuration needs to start at Python 3.9.\n\nThis PR:\n- raises the package Python floor to 3.9\n- removes cp38 from cibuildwheel build and test-skip selectors\n- updates the CI test matrix Python 3.8 leg to Python 3.9"
    },
    {
      "commit": "fc275d6f4de391e0d51f2097cc601d56a5d88bd3",
      "tree": "b2a8ac752ec3ce3eebeee210a46d01962d988486",
      "parents": [
        "0d19ec173c12dbeda41b5d2541d31d83b6ad1160"
      ],
      "author": {
        "name": "Yaxing Cai",
        "email": "caiyaxing666@gmail.com",
        "time": "Thu Jun 18 22:38:25 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jun 18 10:38:25 2026 -0400"
      },
      "message": "[CI] Update Jimver/cuda-toolkit to allowed ref v0.2.35 (#631)\n\n## Motivation\n\nThe ASF `infrastructure-actions` allowlist was updated and the\n`Jimver/cuda-toolkit` ref currently pinned in our CI was removed:\n\n- Removed:\n`Jimver/cuda-toolkit@6008063726ffe3309d1b22e413d9e88fed91a2f2`\n\nSince this ref is no longer on the approved list, the ASF\naction-allowlist check fails for `torch_c_dlpack.yml`.\n\n## Change\n\nBump `Jimver/cuda-toolkit` to the latest allowed ref:\n\n- New: `Jimver/cuda-toolkit@3d45d157f327c09c04b50ee6ccdea2d9d017ec76`\n(v0.2.35)\n\nThis is the newest `cuda-toolkit` ref on the allowlist and the only one\nwithout an `expires_at`, so it is the most durable choice. The step only\nconsumes the stable `CUDA_PATH` output (no `with:` inputs), so the bump\nneeds no other changes.\n\n## Notes\n\nThis is a follow-up to the action-ref hygiene sweep. The\npreviously-expired `astral-sh/setup-uv` (#624) and `pypa/cibuildwheel`\n(#626) refs have already been bumped on `main`; `Jimver/cuda-toolkit`\nwas the only remaining ref flagged by the ASF allowlist checker.\n\nVerified with the official `apache/infrastructure-actions`\n`check_asf_allowlist.py` against the current `approved_patterns.yml`: 0\nviolations after this change."
    },
    {
      "commit": "0d19ec173c12dbeda41b5d2541d31d83b6ad1160",
      "tree": "0c1abef25e900bf50442011d25d6fef93c21486c",
      "parents": [
        "99238160e31395aff007a951a09b61fd4f4526e3"
      ],
      "author": {
        "name": "Yaxing Cai",
        "email": "caiyaxing666@gmail.com",
        "time": "Thu Jun 18 22:37:55 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Jun 18 10:37:55 2026 -0400"
      },
      "message": "[FIX] Avoid -Wassume error in structural visit VisitImpl (#632)\n\n## Problem\n\nThe macOS clang CI job on `main` fails to compile with `-Werror`:\n\n```\ninclude/tvm/ffi/extra/structural_visit.h:575:29: error: the argument to\n\u0027__builtin_assume\u0027 has side effects that will be discarded [-Werror,-Wassume]\n    TVM_FFI_UNSAFE_ASSUME(result.type_index() \u003d\u003d TypeIndex::kTVMFFIInt);\n```\n\n## Root cause\n\nclang\u0027s `__builtin_assume` discards its argument\u0027s side effects, so\n`-Wassume` rejects any argument that **contains a call expression** —\nthis is a purely syntactic check, independent of whether the call is\nactually pure.\n\nThis is a regression from #629, which inlined `result.type_index()`\ndirectly into `TVM_FFI_UNSAFE_ASSUME` to silence `-Wunused-variable`.\nThe two warnings pull in opposite directions:\n\n| | `-Wunused-variable` | `-Wassume` |\n|---|---|---|\n| pre-#629 (local var) | ❌ (when assume macro is a no-op) | ✅ |\n| #629 (inlined call) | ✅ | ❌ ← CI fails |\n| this PR | ✅ | ✅ |\n\nNote `result` here is a C++ `Expected`, so `result.type_index()` is a\n**method call**. The other 10 `TVM_FFI_UNSAFE_ASSUME` sites in the tree\noperate on the raw `TVMFFIAny` C struct via the plain field\n`src-\u003etype_index`, which contains no call expression and is therefore\nunaffected. This was the only call-expression assume site in the\ncodebase.\n\n## Fix\n\nHoist the call back into a local and mark it `[[maybe_unused]]`:\n\n```cpp\n[[maybe_unused]] int32_t type_index \u003d result.type_index();\nTVM_FFI_UNSAFE_ASSUME(type_index \u003d\u003d TypeIndex::kTVMFFIInt);\n```\n\n- The assume argument is now a plain variable read → satisfies\n`-Wassume`.\n- `[[maybe_unused]]` keeps `-Wunused-variable` quiet on configs where\nthe assume macro compiles away to a no-op → satisfies what #629 was\noriginally fixing.\n\n## Validation\n\n- `clang++ -std\u003dc++17 -Werror -Wassume -fsyntax-only\nsrc/ffi/extra/structural_visit.cc` (Homebrew clang 22): **passes** after\nthe change, **fails** before it (reproduces the CI error).\n- Confirmed `[[maybe_unused]]` suppresses `-Wunused-variable` when the\nassume macro expands to a no-op.\n- `clang-format` clean; lines within the 100-col limit."
    },
    {
      "commit": "99238160e31395aff007a951a09b61fd4f4526e3",
      "tree": "51b016023fe216d73ab8e3592cf5fbf7849e871f",
      "parents": [
        "3d2743325eed70d0c206f8b7f548be87a18f86b6"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Wed Jun 17 13:45:11 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jun 17 13:45:11 2026 -0400"
      },
      "message": "Avoid unused type_index local in structural visit (#629)\n\nThis removes the local `type_index` variable in\n`StructuralWalkCallbackVisitorObj::VisitImpl` and passes the type\npredicate directly to `TVM_FFI_UNSAFE_ASSUME`.\n\nThe previous local could trigger `-Wunused-variable` under\nconfigurations where the unsafe-assume macro compiles away or does not\ncount as a use, causing warning-as-error builds to fail.\n\nValidation:\n- `git diff --check`\n- `pre-commit run --files include/tvm/ffi/extra/structural_visit.h`"
    },
    {
      "commit": "3d2743325eed70d0c206f8b7f548be87a18f86b6",
      "tree": "09557ebf9f55cc25e6ca7a60a104d3f42f9b9d6c",
      "parents": [
        "e3bcb8d88fbf520e3377f963a7616ad3a67af587"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Wed Jun 17 11:51:20 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jun 17 11:51:20 2026 -0400"
      },
      "message": "[CMake] Format static symbol helper condition (#628)\n\nApply cmake-format to the condition introduced for hiding symbols from\nlinked static libraries.\n\nValidation:\n- pre-commit run cmake-format --files cmake/Utils/Library.cmake\n- git diff --check"
    },
    {
      "commit": "e3bcb8d88fbf520e3377f963a7616ad3a67af587",
      "tree": "29d2aa0c770a981018721092a949877834992046",
      "parents": [
        "a2c0b6cac9c71d460a70ce744cda0ad6d2d49494"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Wed Jun 17 11:45:56 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jun 17 11:45:56 2026 -0400"
      },
      "message": "[BUILD] Hide symbols from linked static libraries (#627)\n\nTo avoid downstream mistakenly picking up symbols from static\nlibstdc++_nonshared, always hide symbols from static libraries linked\ninto tvm-ffi shared objects.\n\nThis adds a CMake helper for the policy and applies it to\ntvm_ffi_shared, tvm_ffi_testing, and the optional tvm_ffi_cython target\non ELF platforms.\n\nLocal validation:\n- Configured and built tvm_ffi_shared and tvm_ffi_testing with\nTVM_FFI_USE_LIBBACKTRACE\u003dOFF.\n- Verified generated Ninja link flags include -Wl,--exclude-libs,ALL for\nlibtvm_ffi.so and libtvm_ffi_testing.so."
    },
    {
      "commit": "a2c0b6cac9c71d460a70ce744cda0ad6d2d49494",
      "tree": "bc07c8a15daf62b2cb9eaf3d848ef00ebc3a068c",
      "parents": [
        "4f1cbdc1d21cf547678946856d2625701f50b05b"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Wed Jun 17 11:34:14 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jun 17 11:34:14 2026 -0400"
      },
      "message": "[CI] Bump pinned GitHub Action hashes (#626)\n\nBump the pinned cibuildwheel GitHub Action hash to pypa/cibuildwheel\nv4.1.0.\n\nThe pypa/gh-action-pypi-publish and pre-commit/action pins were already\nat the requested hashes."
    },
    {
      "commit": "4f1cbdc1d21cf547678946856d2625701f50b05b",
      "tree": "1255152b04676c34bb046b7bc152bc6b7ebe6470",
      "parents": [
        "f9041046820c04e585a4942cb88cda571380be79"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Wed Jun 17 11:33:49 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jun 17 11:33:49 2026 -0400"
      },
      "message": "[DOCS] Clarify CStrParts error handling usage (#625)\n\nSummary:\n- Clarify that TVMFFIErrorSetRaisedFromCStrParts is for assembling error\nmessages from reusable parts, not for non-null-terminated strings with\nexplicit lengths."
    },
    {
      "commit": "f9041046820c04e585a4942cb88cda571380be79",
      "tree": "8753014e4583c40bb7ce2d1ffa8aa30f38894e90",
      "parents": [
        "807b17af33b04899f1ec676f1c4bf380fcfcf4a0"
      ],
      "author": {
        "name": "Yaxing Cai",
        "email": "caiyaxing666@gmail.com",
        "time": "Wed Jun 17 17:09:42 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jun 17 17:09:42 2026 +0800"
      },
      "message": "[CI] Update astral-sh/setup-uv to allowed ref v8.2.0 (#624)\n\n## Motivation\n\nThe ASF `infrastructure-actions` allowlist was updated and the\npreviously pinned `astral-sh/setup-uv` ref was removed:\n\n- Removed: `astral-sh/setup-uv@5a095e7a2014a4212f075830d4f7277575a9d098`\n(v7.3.1)\n\nSince this ref is no longer on the approved list, the action allowlist\ncheck will reject our workflows until it is bumped to a currently\nallowed ref.\n\n## Change\n\nBump all usages of `astral-sh/setup-uv` to the latest allowed ref:\n\n- New: `astral-sh/setup-uv@fac544c07dec837d0ccb6301d7b5580bf5edae39`\n(v8.2.0)\n\nThis is the newest ref currently on the allowlist and the only\n`setup-uv` entry without an `expires_at`, so it is the most durable\nchoice. The v7.x allowed refs expire on 2026-06-27.\n\nThe change is a straightforward pin update — the workflows only use the\nstable `python-version` and `activate-environment` inputs, which are\nunchanged across the v7 → v8 major bump.\n\n### Files updated (10 occurrences)\n\n- `.github/actions/build-wheel-for-publish/action.yml`\n- `.github/workflows/ci_mainline_only.yml`\n- `.github/workflows/ci_test.yml`\n- `.github/workflows/torch_c_dlpack.yml`"
    },
    {
      "commit": "807b17af33b04899f1ec676f1c4bf380fcfcf4a0",
      "tree": "d3d55981f895b5aa7cdee09e46b335f522699b4c",
      "parents": [
        "8a0b93fbaf13a85aca303e1910ab31eeea7021c8"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Tue Jun 16 12:52:35 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jun 16 09:52:35 2026 -0700"
      },
      "message": "[DOCS] Document Python FFI conversion protocols (#622)\n\nThis documents the Python argument conversion protocols recognized when\ncalling TVM-FFI functions.\n\nSummary:\n- Add a Python guide subsection for argument conversion protocols.\n- Document the supported `__tvm_ffi_*` hooks and `__cuda_stream__` in a\nprotocol table.\n- Point DLPack-compatible objects to the DLPack protocol documentation.\n- Add a cross-reference from the Function and Module concept page.\n\nValidation:\n- `pre-commit run --files docs/guides/python_lang_guide.md\ndocs/concepts/func_module.rst`\n- `uv run --group docs sphinx-build -M html docs docs/_build`"
    },
    {
      "commit": "8a0b93fbaf13a85aca303e1910ab31eeea7021c8",
      "tree": "0b17d31adf2f4073b4bc79a9a4cd277236f4f85b",
      "parents": [
        "c5963d7bfb9c7c30d992d9d95d736cfbb15368a5"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sat Jun 13 14:43:54 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Jun 13 14:43:54 2026 -0400"
      },
      "message": "Adopt AGENTS.md for agent guidance (#620)\n\nAgent instructions should live in vendor-neutral locations so different\ncoding assistants can share the same repo guidance without making\nClaude-specific paths canonical. The existing content already describes\nthe right workflows, but it was rooted under CLAUDE.md and\n.claude/skills.\n\nThis moves the preserved instruction content to AGENTS.md, keeps\nCLAUDE.md as a compatibility symlink, and makes .agents/skills the\ncanonical repo-local skill directory. The Claude skills path now points\nback to .agents/skills, the obsolete Claude launch config is removed,\nand lint configuration is updated for the new agent-skill location and\ncompatibility symlink."
    },
    {
      "commit": "c5963d7bfb9c7c30d992d9d95d736cfbb15368a5",
      "tree": "c7bd88b4f0b3a32f4c8403d799456980e2980dd0",
      "parents": [
        "9a863e8a9349cb8be47da31a6c9ae05c2fb92653"
      ],
      "author": {
        "name": "Linzhang Li",
        "email": "Blemiade_Qinchuan@sjtu.edu.cn",
        "time": "Fri Jun 12 10:17:41 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jun 12 10:17:41 2026 -0400"
      },
      "message": "[REFACTOR][STUBGEN] refactor the stubgen logic. (#608)\n\n## Summary\n\nThis PR refactors the Python stubgen implementation to improve\nextensibility and separation of concerns. No functional changes are\nintended, and the generated output should remain unchanged.\n\n## Design\n\nThe current stubgen implementation contains both language-independent\nlogic (e.g., file processing and library analysis) and language-specific\ncode generation. This PR separates these responsibilities by introducing\na generator abstraction for the code generation layer, making it easier\nto support additional target languages in the future.\n\nThe reorganized file structure is:\n\n```text\npython/tvm_ffi/stub/\n├── __init__.py\n├── cli.py\n├── consts.py\n├── file_utils.py\n├── lib_state.py\n├── utils.py\n├── generator.py\n└── python_generator/\n    ├── __init__.py\n    ├── generator.py\n    ├── codegen.py\n    ├── consts.py\n    └── utils.py\n```\n\nThis refactoring lays the groundwork for future support of Rust stub\ngeneration and other language backends.\n\n## Testing\n\nThis PR is a pure refactor and is not expected to change existing\nbehavior. Therefore, no new tests are added.\n\nSigned-off-by: yuchuan \u003cyuchuan.7streams@gmail.com\u003e"
    },
    {
      "commit": "9a863e8a9349cb8be47da31a6c9ae05c2fb92653",
      "tree": "3b341f35cd672e5b4a7ec5808e53fa3544f3f91c",
      "parents": [
        "2309578ec76bf7d26062c43b06e44714d6b33dd0"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Wed Jun 10 13:59:09 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jun 10 13:59:09 2026 -0400"
      },
      "message": "Robustify FromJSONGraph (#619)\n\nBounds-check the node index and add small arity checks so malformed JSON\nraises ValueError instead of reading out of bounds. Covered by a C++\nmalformed-input test."
    },
    {
      "commit": "2309578ec76bf7d26062c43b06e44714d6b33dd0",
      "tree": "7fa723ea7de0d0e3955b482c2e4b9663babbaed5",
      "parents": [
        "7c077e48d21f79033455e4727b17effe004024e2"
      ],
      "author": {
        "name": "Kathryn (Jinqi) Chen",
        "email": "65606304+Kathryn-cat@users.noreply.github.com",
        "time": "Wed Jun 10 05:38:26 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Jun 10 08:38:26 2026 -0400"
      },
      "message": "[FEAT] Add structural visitor and typed structural walk APIs (#601)\n\n## Summary\n\nThis PR adds structural traversal APIs for TVM FFI values in C++ and\nPython.\n\nThe main user-facing addition is `StructuralWalk` /\n`tvm_ffi.structural_walk`, a pytree-style walk that can visit both\nobject-backed nodes and POD leaves (`int`, `float`, `bool`, `str`,\n`bytes`). It supports typed callbacks, pre/post-order traversal, child\nskipping, early interruption, and def-region-aware callbacks.\n\n## Key Changes\n\n- Added C++ `StructuralVisitor`, `VisitInterrupt`, `WalkResult`, and\n`StructuralWalk`.\n- Added Python `tvm_ffi.structural_walk`.\n- Traversal operates on `AnyView`, allowing callbacks to match objects,\ncontainers, and POD values.\n- C++ callbacks dispatch on their first argument and may optionally\naccept a second `TVMFFIDefRegionKind`.\n- Python callbacks are passed as `(type, callback)` entries, with\nsupport for grouped types like `((int, float), callback)`, a single\ncallback catch-all, or a sequence of entries.\n- Python def-region-aware callbacks are passed via\n`with_def_region_kind\u003d` and receive `(value, def_region_kind)`.\n- Added runtime type-index matching for Python callbacks, including\nsubclass matching, `Any` catch-all, `Object` matching, and string/bytes\nstorage variants.\n- Custom structural visit hooks now use `AnyView` for the visited value.\n- Added visit error-context propagation for object-backed nodes when\ntraversal fails.\n\n## Examples\n\nPython:\n\n```python\nvisited \u003d []\n\ndef on_int(value):\n    visited.append(value)\n    if value \u003d\u003d 0:\n        return tvm_ffi.VisitInterrupt(value)\n    return tvm_ffi.WalkResult.ADVANCE\n\nresult \u003d tvm_ffi.structural_walk(root, (int, on_int), order\u003d\"pre\")\n```\n\nGrouped callback types:\n\n```python\ntvm_ffi.structural_walk(\n    root,\n    [\n        ((int, float), on_number),\n        (MyNode, on_node),\n        (object, on_any),\n    ],\n)\n```\n\nDef-region-aware callbacks:\n\n```python\nuses \u003d []\n\ntvm_ffi.structural_walk(\n    func,\n    with_def_region_kind\u003d(\n        Var,\n        lambda var, kind: uses.append(var) if kind \u003d\u003d tvm_ffi.DefRegionKind.NONE else None,\n    ),\n)\n```\n\nC++:\n\n```cpp\nauto result \u003d StructuralWalk\u003cWalkOrder::kPreOrder\u003e(\n    root,\n    [\u0026](const Add\u0026 add) -\u003e Expected\u003cWalkResult\u003e {\n      ++num_adds;\n      return WalkResult::Advance();\n    },\n    [\u0026](const Mul\u0026 mul) -\u003e Expected\u003cWalkResult\u003e {\n      return WalkResult::Skip();\n    });\n```\n\nC++ def-region-aware walk:\n\n```cpp\nList\u003cVar\u003e uses;\nauto result \u003d StructuralWalk\u003cWalkOrder::kPreOrder\u003e(\n    func,\n    [\u0026](const VarObj* var, TVMFFIDefRegionKind kind) -\u003e Expected\u003cWalkResult\u003e {\n      if (kind \u003d\u003d kTVMFFIDefRegionKindNone) {\n        uses.push_back(Var(GetObjectPtr\u003cVarObj\u003e(var)));\n      }\n      return WalkResult::Advance();\n    });\n```\n\n## Testing\n\n- Added C++ tests for structural visitor traversal, def-region hooks,\ncallback dispatch, POD leaves, object pointers, skip/interrupt behavior,\ndef-region-aware callbacks, and error propagation.\n- Added Python tests for typed callbacks, grouped callback types, mixed\ncallback forms, def-region-aware callbacks, nested containers,\n`Any`/`Object` behavior, post-order traversal, skip, and interrupts.\n- Verified C++ structural visitor and visit error-context tests."
    },
    {
      "commit": "7c077e48d21f79033455e4727b17effe004024e2",
      "tree": "a5e31574873400f6ae0b7205d487d9fba1796731",
      "parents": [
        "59da4c0b82af0d499dae34bd89ef010f64d3ff45"
      ],
      "author": {
        "name": "Ruihang Lai",
        "email": "ruihangl@cs.cmu.edu",
        "time": "Tue Jun 09 17:57:39 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Jun 09 17:57:39 2026 -0400"
      },
      "message": "chore(release): Version bump after release v0.1.12 (#617)\n\nVersion bump after release v0.1.12"
    },
    {
      "commit": "59da4c0b82af0d499dae34bd89ef010f64d3ff45",
      "tree": "cd77250f25c6c8cdb8bd0855aca138380ed7c214",
      "parents": [
        "3050b0a7bd48e04f853027c5fa1f5ab7bc20b856"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sat Jun 06 10:03:14 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Jun 06 10:03:14 2026 -0400"
      },
      "message": "[TEST] Relax test_shared_dag_hash_scaling_not_exponential ratio to 4x (#612)\n\nThe timing-based assertion `t19 \u003c\u003d t18 * 2.0` was flaky at microsecond\nscales. CI frequently measures t18~4μs and t19~8μs; at that resolution\nany clock jitter can double the reading, pushing t19 over a 2x ceiling\nwithout any algorithmic regression.\n\nRaising the threshold to 4x removes the false-positive noise while still\ncatching true exponential blow-up: without memoization the ratio\ncompounds\nfar past 4x within a few depth steps, so the test retains its intended\ndiagnostic value.\n\nFailing CI example:\nAssertionError: Unexpected super-linear scaling: d18\u003d0.000004s\nd19\u003d0.000008s"
    },
    {
      "commit": "3050b0a7bd48e04f853027c5fa1f5ab7bc20b856",
      "tree": "4d84cf6c827b02ac608346dbdb1db39091c62b29",
      "parents": [
        "8e32a61eec2e6e0e6d7c8aa1324f22354d5c32ca"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Fri Jun 05 21:19:17 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jun 05 21:19:17 2026 -0400"
      },
      "message": "[FIX] Drop test_empty_tensor_attributes (numpy dlpack stride change) (#607)\n\nNumPy silently changed how it exports strides for zero-element arrays\nvia\n`__dlpack__`. For a shape `(4, 0, 4)` array NumPy previously reported\nstrides `(0, 4, 1)`, but now reports `(0, 0, 0)`. Either choice is\narguably valid — any stride values are consistent when the array has\nzero\nelements — but `tvm_ffi.from_dlpack` faithfully forwards whatever the\nupstream exporter provides. The test was asserting a NumPy-side\nimplementation detail that has since changed, so it is removed rather\nthan\npatched. Deciding what the correct empty-array stride convention should\nbe\nis a separate question not in scope for this fix."
    },
    {
      "commit": "8e32a61eec2e6e0e6d7c8aa1324f22354d5c32ca",
      "tree": "6012c28f2a7bdc564bc5b8f6ec8dc417e3caa39a",
      "parents": [
        "8ccfe1b9d05fb7e067f8d5b98ac60159c23bb35e"
      ],
      "author": {
        "name": "Kaining Zhong",
        "email": "44538064+kainzhong@users.noreply.github.com",
        "time": "Thu Jun 04 23:11:09 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Jun 05 14:11:09 2026 +0800"
      },
      "message": "feat(python): add tensor methods to align with C++ APIs (#604)\n\nSome of the commonly used tensor methods (`ndim`, `numel`, etc.) are\nprovided in C++ APIs but not in python APIs. Adding these would make it\nhandy especially for users who are familiar with pytorch APIs.\n\n---------\n\nSigned-off-by: Kaining Zhong \u003ckainingz@nvidia.com\u003e"
    },
    {
      "commit": "8ccfe1b9d05fb7e067f8d5b98ac60159c23bb35e",
      "tree": "cd542d7aa1f11e3d84b5554a130a40507f81d3d0",
      "parents": [
        "ce262f17bd309e9fc313c1523115fd3949d4ef17"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sat May 30 16:52:38 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat May 30 13:52:38 2026 -0700"
      },
      "message": "[CORE] Make AnyView trivially copyable — match C-ABI struct passing (#602)\n\n[CORE] Make AnyView trivially copyable — match C-ABI struct passing\n\nDefault AnyView\u0027s move constructor and move assignment so the type\nis std::is_trivially_copyable_v\u003cAnyView\u003e. AnyView owns nothing, so\nthe prior \"reset source to None after move\" body was dead semantics.\n\nMotivation\n----------\nA trivially-copyable C++ aggregate is passed by the C++ compiler\nusing the same calling convention as the equivalent C struct of POD\ntypes. That makes function signatures like `void fn(AnyView)`\nABI-stable across every language that interoperates via the C ABI —\nRust, Go, Python ctypes, etc. can call C++ functions that take\nAnyView by value using their native FFI, with no wrapper or shim.\nThe 16-byte AnyView is treated identically to a C\n`struct { int32_t type_index; uint32_t zero_padding; int64_t v_int64; }`\nor a Rust `#[repr(C)] struct { i32, u32, i64 }`.\n\nA user-defined move ctor disqualifies that classification, forcing\nthe compiler to fall back to passing AnyView by hidden reference (a\nC++-specific calling convention) — silently breaking cross-language\nABI compatibility for any signature that takes AnyView by value.\n\nAs a follow-on benefit, on x86-64 SysV / AAPCS AArch64 the trivially-\ncopyable AnyView is now passed in two integer registers instead of\nvia a stack pointer, eliminating a memory dereference per dispatch.\n\nResult\n------\nCodegen for `int fn(AnyView x) { return x.type_index(); }` on\nx86-64 SysV (-O2, gcc 11.4):\n\n  BEFORE:  mov eax, DWORD PTR [rdi]   ; deref of caller stack slot\n  AFTER :  mov eax, edi               ; type_index lives directly in rdi\n\nA `static_assert(std::is_trivially_copyable_v\u003cAnyView\u003e, ...)` is\nadded next to the existing size asserts so any future user-defined\ncopy/move/destructor that regresses this property fails at compile\ntime.\n\nNotes\n-----\n- Any (the owning sibling) is a separate class — not a subclass —\n  and remains non-trivially-copyable via its refcount-decrementing\n  destructor. The static_assert is fully local to AnyView.\n- No test churn required: no existing test asserted the moved-from\n  AnyView reset-to-None semantics.\n- No ABI break: of the 21 TVM_FFI_EXTRA_CXX_API declarations in\n  include/tvm/ffi/extra/*, none currently takes AnyView by value\n  (all take `const Any\u0026` or project-specific types), and the C ABI\n  in c_api.h uses `const TVMFFIAny*` pointers. So this calling-\n  convention flip does not break any existing exported API."
    },
    {
      "commit": "ce262f17bd309e9fc313c1523115fd3949d4ef17",
      "tree": "3bfc4b430067a0c3e42067c40c9a7fdb320f1d1f",
      "parents": [
        "1007269cd9e243fc9a20a2026a79503ab30e2b58"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Thu May 28 18:12:12 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu May 28 15:12:12 2026 -0700"
      },
      "message": "[CI] Use uv tool run for sdist build instead of pipx (#600)\n\n## Summary\n\nThe `Build sdist` step in\n`.github/actions/build-wheel-for-publish/action.yml`\nwas invoking `pipx run build` and `pipx run twine`, which broke against\nthe\nrunner\u0027s current uv toolchain. The rest of the composite action already\nprovisions uv via `astral-sh/setup-uv`, so this PR switches the sdist\nstep\nto `uv tool run` and removes the pipx dependency.\n\n## Changes\n\n- `.github/actions/build-wheel-for-publish/action.yml`:\n- `pipx run build --sdist ...` -\u003e `uv tool run --from build\npyproject-build --sdist ...`\n- `pipx run twine check ...` -\u003e `uv tool run --from twine twine check\n...`"
    },
    {
      "commit": "1007269cd9e243fc9a20a2026a79503ab30e2b58",
      "tree": "88e3958b121307ed6520d9c05226918312ab8f0a",
      "parents": [
        "1e8c998269e8667b35c576bbaeb37fadb94593b1"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Thu May 28 13:33:31 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu May 28 13:33:31 2026 -0400"
      },
      "message": "[FEAT] Streamline AccessPath/AccessStep print format (#598)\n\n## Summary\n\nRegister a custom `__ffi_repr__` for `ffi::reflection::AccessPath` and\n`AccessStep` so their formatted output is a concise, human-readable path\nexpression:\n\n```\n\u003croot\u003e.config.layers[0][\u003cmissing:\"weights\"\u003e]\n```\n\nPer-step rendering:\n- root: `\u003croot\u003e`\n- attr: `.name`\n- array item: `[index]`\n- map item: `[\u003crepr(key)\u003e]` (string keys quoted)\n- missing attr: `[\u003cmissing:\"name\"\u003e]`\n- missing array: `[\u003cmissing:index\u003e]`\n- missing map: `[\u003cmissing:\u003crepr(key)\u003e\u003e]`\n\nThe formatter delegates key quoting to the existing `EscapedStringPy`\npath via `fn_repr(step-\u003ekey)`, so non-string map keys are also handled\nrobustly."
    },
    {
      "commit": "1e8c998269e8667b35c576bbaeb37fadb94593b1",
      "tree": "87898032551a721ee6774bc919ce50fa88961537",
      "parents": [
        "98d0029dd4e002da1516d43f9b92e792f139e709"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Thu May 28 13:23:27 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu May 28 13:23:27 2026 -0400"
      },
      "message": "[FEAT] Optimize Expected\u003cT\u003e for minimal compiled code and efficiency (#599)\n\n## Summary\n\nOptimize `Expected\u003cT\u003e` so the happy paths compile down to a handful of\ninstructions. The previous implementation routed `is_ok` / `is_err`\nthrough `as\u003cError\u003e()` (which refcount-bumped the Error tag just to test\ntype), and `value()` went through `cast\u003cT\u003e()` which performed a\nredundant runtime type check on every read.\n\n## Changes\n\n- `is_ok()` / `is_err()` read the type-index discriminator directly. No\nindirection.\n- `value()` and `error()` use `TVM_FFI_PREDICT_TRUE/FALSE` to hint the\nhappy path; the type-traits read uses the `*AfterCheck` variants since\nthe `Expected` invariant already guarantees the held type.\n- `value_or()` gains an rvalue overload that moves from the held value\ninstead of copying when the `Expected` is consumed as a temporary.\n- Add `TVM_FFI_UNSAFE_ASSUME` macro (alongside `TVM_FFI_PREDICT_*`)\nexpanding to `__builtin_assume` / `__assume`. Applied inside non-Object\n`CopyFromAnyViewAfterCheck` to hint the compiler about the type-index\ninvariant.\n- Add `MoveFromAnyAfterCheck` to `TypeTraits\u003cDLDataType\u003e`; the gap\nprevented `Expected\u003cDLDataType\u003e::value() \u0026\u0026` from compiling. POD type,\nso delegate to `CopyFromAnyViewAfterCheck`.\n- Add `MoveFromAnyAfterCheck` to `TypeTraits\u003cTypedFunction\u003cFType\u003e\u003e`;\ndelegate to `TypeTraits\u003cFunction\u003e::MoveFromAnyAfterCheck`.\n\n## Codegen (clang++-17 -O2, lines of asm, lower is better)\n\n| Probe | Before | After |\n|---|---|---|\n| is_ok / is_err (int) | 173 | 5 |\n| value() lvalue (int) | 696 | 37 |\n| value() rvalue (int) | 725 | 34 |\n| value() rvalue (String) | 810 | 96 |\n| value() rvalue (Array\u003cint\u003e) | 1763 | 107 |\n| make_ok().value() | 738 | 50 |\n| std::move(make_ok()).value() | 738 | 50 |\n\n`make_ok().value()` compiles bit-identical to\n`std::move(make_ok()).value()` — the prvalue temporary materializes an\nxvalue, binding the `\u0026\u0026` overload directly. No `std::move` needed at the\ncall site."
    },
    {
      "commit": "98d0029dd4e002da1516d43f9b92e792f139e709",
      "tree": "629b5ac66f2ce52208d968b202e3e93e9c1225eb",
      "parents": [
        "a6071f671364563012cd830c98d6df1d935f880f"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Wed May 27 09:54:06 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed May 27 09:54:06 2026 -0400"
      },
      "message": "[FEAT][FFI] Add ostream operator\u003c\u003c for Any/ObjectRef/Variant/Optional (#596)\n\n## Summary\n\nThe four type-erased FFI value containers (`ffi::Any`, `ffi::ObjectRef`,\n`ffi::Variant\u003cTs...\u003e`, `ffi::Optional\u003cT\u003e`) have no `operator\u003c\u003c` for\n`std::ostream`, requiring manual `.ToString()` / `ReprPrint()` calls.\nThis PR adds four inline overloads in\n`include/tvm/ffi/extra/dataclass.h` that delegate to the existing\n`ReprPrint(Any)` machinery, so `std::cout \u003c\u003c x` and `LOG(INFO) \u003c\u003c x`\njust work.\n\n- `operator\u003c\u003c(ostream\u0026, const Any\u0026)` — delegates to `ReprPrint(value)`\n- `operator\u003c\u003c(ostream\u0026, const ObjectRef\u0026)` — delegates to\n`ReprPrint(Any(value))`; derived types still print their type-specific\nrepr via runtime `type_index` dispatch\n- `operator\u003c\u003c(ostream\u0026, const Variant\u003cTs...\u003e\u0026)` — delegates to\n`ReprPrint(Any(value))`\n- `operator\u003c\u003c(ostream\u0026, const Optional\u003cT\u003e\u0026)` — prints `\"None\"` for empty\n(Python convention), otherwise `ReprPrint(Any(value))`\n\nPre-existing `String` and `Shape` `operator\u003c\u003c` overloads are unaffected:\n`Shape` (a derived `ObjectRef`) wins over the generic `const ObjectRef\u0026`\noverload via overload resolution; `String` is not an `ObjectRef`\nsubclass and has no conflict."
    },
    {
      "commit": "a6071f671364563012cd830c98d6df1d935f880f",
      "tree": "e44fcec24b5f3b0835b2ad09d0f16c855d0ea622",
      "parents": [
        "35c99d0ac4cb784862115d0089f60c603acec8f9"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Thu May 21 14:32:20 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu May 21 14:32:20 2026 -0700"
      },
      "message": "[EXTRA][FEAT] VisitErrorContext for visit-context-aware error reporting (#587)\n\n## Summary\n\nIntroduces `VisitErrorContext`, a typed payload for\n`Error::extra_context` that records the chain of `ObjectRef` nodes\nvisited during a recursive visit when an error is thrown. This enables\nvisit-context-aware error reporting with structured access paths.\n\n### Key components\n\n- **`VisitErrorContextObj` / `VisitErrorContext`**\n(`include/tvm/ffi/extra/visit_error_context.h`): Object/Ref pair that\nstores `reverse_visit_pattern` (the breadcrumb chain of visited nodes,\ninnermost-first) and `prev_error_context` (any pre-existing error\ncontext that was displaced).\n\n- **Macros** for instrumenting recursive visits:\n- `TVM_FFI_VISIT_BEGIN()` / `TVM_FFI_VISIT_END(node)`: Wrap a visit body\nin a try/catch that appends `node` to the error context on unwind.\n- `TVM_FFI_VISIT_THROW(ErrorKind, node)`: Throw an error with `node` as\nthe innermost frame of the context (for pinpointing a child field as the\nerror site).\n\n- **`VisitErrorContext::FindAccessPaths(root, ctx)`**: Resolves the\nbreadcrumb chain against a tree rooted at `root`, producing\n`reflection::AccessPath` instances (e.g., `.body[2].cond.lhs`) for\nricher error messages.\n\n- **`VisitErrorAccessPathFinder`** (internal, in `.cc`): DFS matcher\nthat walks the tree using reflection field info, matching the breadcrumb\npattern with support for Attr/ArrayItem/MapItem access kinds, CSE\nmulti-match, sparse anchors, prefix matching, and\nconsecutive-duplicate/null cleanup.\n\n### Tests\n\nComprehensive GoogleTest coverage in\n`tests/cpp/extra/test_visit_error_context.cc`:\n- Layer A (Macro to Chain): `MacroBuildsChain`,\n`MacroPreExistingPayloadWrap`, `MacroThrowBuildsChain`\n- Layer B (Chain to AccessPaths): `BasicMatch`, `AccessKindCoverage`,\n`SparsePatternAnchors`, `PartialChain`, `EdgeCases`, `RecordsCleanup`\n- Integration: `TryGetFromError`"
    },
    {
      "commit": "35c99d0ac4cb784862115d0089f60c603acec8f9",
      "tree": "3cd9b09a139ec915da02975c8be3f4bdf4d50e78",
      "parents": [
        "d73a26783488430986fd855ae67ff7a9fb016413"
      ],
      "author": {
        "name": "Gabriel Wu",
        "email": "13583761+lucifer1004@users.noreply.github.com",
        "time": "Fri May 15 22:59:45 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri May 15 10:59:45 2026 -0400"
      },
      "message": "[FIX][RUST] use `$crate::` in tvm_ffi_dll_export_typed_func! and ensure! (#590)"
    },
    {
      "commit": "d73a26783488430986fd855ae67ff7a9fb016413",
      "tree": "c50a5d44560434fbaaf027295ca3fcc49f2378cd",
      "parents": [
        "d4cfd86ecfb4cc8e769412627ad768e43093b21b"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Wed May 13 22:21:33 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed May 13 22:21:33 2026 -0400"
      },
      "message": "[BUILD] TVM_FFI_COLD_CODE / TVM_FFI_PREDICT_FALSE macros and cold-marking of error paths (#589)\n\n## Summary\n\nAdds three header-only macros (`TVM_FFI_COLD_CODE`,\n`TVM_FFI_PREDICT_FALSE`, `TVM_FFI_PREDICT_TRUE`) in\n`tvm/ffi/base_details.h` and applies them to a small audited set of\nerror-only helpers. No CMake changes.\n\n## What\n\n`TVM_FFI_COLD_CODE`: `[[gnu::cold]]` on GCC/Clang, no-op on MSVC.\n`TVM_FFI_PREDICT_FALSE` / `TVM_FFI_PREDICT_TRUE`: `__builtin_expect` on\nGCC/Clang, no-op on MSVC.\n\nCold-marked (error / setup / teardown only):\n\n- `details::ErrorBuilder` ctors and the `[[noreturn]]` destructor\n- `TVMFFISegFaultHandler`\n- `TVMFFIInstallSignalHandler`\n- `ForwardPyErrorToFFI`\n\nC ABI exports stay hot per cross-DSO surface hygiene — `TVMFFIError*`\nfamily, `TVMFFIBacktrace`, and `SafeCallContext` setters all remain\nordinary entry points. Deleters are not cold-marked: they run on every\ncallback destruction during normal program operation, not on an error\npath.\n\n`TVM_FFI_PREDICT_FALSE` is applied to `TVM_FFI_CHECK_SAFE_CALL`,\n`TVM_FFI_CHECK`, and ~17 error-check branches in the Python→FFI\ndispatchers in `tvm_ffi_python_helpers.h`.\n\n## Mechanism\n\nGCC and Clang emit cold-marked functions into per-TU `.text.unlikely`.\nThe default GNU linker script\u0027s `*(.text.unlikely .text.*_unlikely\n.text.unlikely.*)` rule gathers them into a contiguous slot inside\n`.text`. No `-ffunction-sections` flag required.\n\nDetailed measurements (binary-size matrix, isolation study, perf table,\ncold-cluster bounds) posted as a follow-up comment."
    },
    {
      "commit": "d4cfd86ecfb4cc8e769412627ad768e43093b21b",
      "tree": "572ab3154a211fd1570766e0c30e27ba4dc7aa45",
      "parents": [
        "4dbc2602ff1463d0ce14e2cc48218702e98262d6"
      ],
      "author": {
        "name": "DarkSharpness",
        "email": "76582120+DarkSharpness@users.noreply.github.com",
        "time": "Wed May 13 22:46:11 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed May 13 10:46:11 2026 -0400"
      },
      "message": "[Minor] log ninja result (#584)\n\nshould fix #565"
    },
    {
      "commit": "4dbc2602ff1463d0ce14e2cc48218702e98262d6",
      "tree": "09e2a2b6f5d1329bf61af5fe59a47b9711ad310d",
      "parents": [
        "fb5ad97ad629763f893d7fe593f6b096d0baa737"
      ],
      "author": {
        "name": "ZihaoMu",
        "email": "zmu@amd.com",
        "time": "Wed May 13 22:41:57 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed May 13 10:41:57 2026 -0400"
      },
      "message": "[BugFix][ROCm] Prefer upstream PyTorch DLPack API in torch extension loader (#585)\n\nMotivation:\n- If PyTorch already provides `__dlpack_c_exchange_api__`, tvm-ffi uses\nit directly on all backends.\n- The optional `torch-c-dlpack-ext` path is only used as a fallback for\nolder PyTorch builds that do not provide the API.\n- The fallback extension library name is selected with backend-aware\ndetection for CPU, CUDA, and ROCm.\n\nTests are added for backend detection, ROCm short-circuit behavior when\nPyTorch already provides the API, and GPU tensor metadata through\nDLPack.\n\n\nRelated PR: https://github.com/tile-ai/tilelang/pull/2179, I have\nfinished the A/B test locally."
    },
    {
      "commit": "fb5ad97ad629763f893d7fe593f6b096d0baa737",
      "tree": "3baa50e5f71fcfe10d5077cfb45af612be7a5752",
      "parents": [
        "de93d564a13c7f4d74255b907dd2370ad9874cd8"
      ],
      "author": {
        "name": "Yaxing Cai",
        "email": "caiyaxing666@gmail.com",
        "time": "Tue May 12 21:01:49 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue May 12 21:01:49 2026 +0800"
      },
      "message": "[REFACTOR][OrcJIT] Per-session slab-pool memory manager (#574)\n\n## Summary\n\nRefactors the `tvm_ffi_orcjit` addon along three axes — memory\nlifecycle,\nLLVM-workaround isolation, and macOS/Windows enablement. 14 commits,\neach\nindependently revertible.\n\n## What changed\n\n**Memory lifecycle.** The fixed ~1 GB per-session arena becomes a\ngrowable\npool of fixed-size `Slab`s. Dropping a `DynamicLibrary` now calls\n`removeJITDylib` and actually frees its JIT pages (previously code\naccumulated until session destruction). `Session.clear_free_slabs()`\nreleases drained slabs back to the OS. `orcjit_memory_manager.cc` shrank\n~740 → 174 lines with `Slab` pulled into its own `orcjit_slab.{h,cc}`.\n\n**LLVM-workaround isolation.** Every upstream-LLVM workaround — formerly\ninlined in `orcjit_session.cc` — moved into `llvm_patches/` (5 modules:\n`gotpcrelx_fix`, `init_fini_plugin`, `macho_cxa_atexit_shim`,\n`win_coff_pdata_strip`, `win_dll_import_generator`). Each has a\nfixed-shape\nheader with issue links, trigger, symptom, and a `## Removal` checklist\nso\nit\u0027s mechanically deletable once upstream fixes land.\n`orcjit_session.cc`\nshrank ~870 → 320 lines of pure orchestration.\n\n**macOS + Windows enablement.** macOS: skip `MachOPlatform` to sidestep\nthe\ncompact-unwind 32-bit-delta bug, and interpose `___cxa_atexit`\nper-JITDylib\nwith a TLS-routed shim that drains at dylib drop. Windows: stub DLL\nimports\nthrough JIT-allocated PLT entries (keeps PCRel32 in range) and strip\n`.pdata` / `.xdata` relocations pre-graph-build. The three-platform\nstrategy is documented inline in each patch header.\n\n**Function lifetime + perf.** Captured `Function` values hold a ref to\nthe\nowning dylib so JIT pages survive as long as the handle.\n`FunctionObj::safe_call` binds directly to the JIT\u0027d thunk, eliminating\na\nper-call indirection.\n\n## API\n\n- **Break**: `ExecutionSession(arena_size\u003d…)` →\n`ExecutionSession(slab_size\u003d…)`.\nSize is per-slab, default 64 MB; `-1` disables the pool (LLJIT falls\nback\n  to scattered mmap).\n- **New**: `ExecutionSession.clear_free_slabs() -\u003e int` — reclaims\ndrained\n  slabs, returns the count.\n\n## Test plan\n\n- [x] aarch64 Linux: `pytest addons/tvm_ffi_orcjit/tests`\n- [x] macOS arm64: 99 passed, 42 skipped\n- [ ] CI: lint / clang-tidy / Windows / x86_64 Linux"
    },
    {
      "commit": "de93d564a13c7f4d74255b907dd2370ad9874cd8",
      "tree": "d7e163f18aed37bf62ad3fcff306d5088df4ef5f",
      "parents": [
        "6f1b459532bd54c942cda3d932ea4f3f629c6df0"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon May 11 12:57:02 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon May 11 12:57:02 2026 -0400"
      },
      "message": "[FEAT] Split SEqHashDef into recursive and non-recursive variants (#583)\n\nThe single SEqHashDef flag treated every nested free var inside a\ndef-region field as a fresh def. That conflates two different binding\nshapes:\n\n- Recursive (function parameters): the value var and any free vars\n  inside its sub-fields are co-introduced at the same binding site.\n\n- Non-recursive (normal binding): only the immediate value var binds;\n  free vars in the var\u0027s sub-fields are use references that must\n  resolve against an outer-scope binding.\n\nThis PR splits the flag in two so each binding shape can be expressed\ndirectly, and updates the structural-equal / structural-hash machinery\nto distinguish them when descending into a FreeVar\u0027s own sub-fields.\nThe custom `__ffi_s_equal__` / `__ffi_s_hash__` callback signature\ngains a typed kind for the def-mode argument; legacy callers passing\na bool continue to compile and preserve their meaning via the standard\nbool-\u003eint coercion (true -\u003e 1 \u003d Recursive, false -\u003e 0 \u003d None).\n\nThe Cython / Python bindings mirror the rename and add the new\nnon-recursive flag to the dataclass field vocabulary. Regression tests\ncover the four recursive / non-recursive corner cases on a new\n`TDefHolder` test type whose `def_recursive` and `def_non_recursive`\nfields hold a FreeVar with a nested FreeVar sub-field."
    },
    {
      "commit": "6f1b459532bd54c942cda3d932ea4f3f629c6df0",
      "tree": "daf1ed603d9baa860c8a8f37c6fa1546947678e4",
      "parents": [
        "acd24bb63ab90b21b186b4cd44e02b6fdbf38525"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun May 10 17:36:25 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun May 10 14:36:25 2026 -0700"
      },
      "message": "[FEAT][REFLECTION] Add tvm::ffi::reflection::overload_cast to pick overloaded function (#582)\n\n## Summary\n\nIntroduce `tvm::ffi::reflection::overload_cast\u003cArgs...\u003e` — a `constexpr`\nhelper for picking a specific overload of an overloaded callable by\nspelling out a parameter-type prefix that uniquely identifies it.\nTrailing parameter types (if any) are deduced from the picked overload\u0027s\nsignature. The result is a typed function pointer (member or free)\nusable wherever a typed fn ptr is required, including as a non-type\ntemplate argument.\n\nIf the prefix matches multiple overloads, the call is ambiguous and the\ncaller spells more parameters until exactly one overload matches.\nConst-qualified members are picked via the\n`tvm::ffi::reflection::const_` tag."
    },
    {
      "commit": "acd24bb63ab90b21b186b4cd44e02b6fdbf38525",
      "tree": "add45cb02ec3d3a11c788d22ae0a9544f7c01b2e",
      "parents": [
        "5caf5082d748542b8af5745f721e10d4bac25c2c"
      ],
      "author": {
        "name": "Yixin Dong",
        "email": "ubospica@gmail.com",
        "time": "Tue May 05 17:35:57 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue May 05 17:35:57 2026 -0400"
      },
      "message": "Update ML infrastructure section with XGrammar link (#581)\n\nAdded link to XGrammar in the ML infrastructure section.\n\n---------\n\nCo-authored-by: gemini-code-assist[bot] \u003c176961590+gemini-code-assist[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "5caf5082d748542b8af5745f721e10d4bac25c2c",
      "tree": "bb0dc6a045a51d639ebfd0a7354f0829e116f7de",
      "parents": [
        "b4525d2bb0e1c0190d3d1bdf46711ee5dd1c4889"
      ],
      "author": {
        "name": "Yong Wu",
        "email": "yongcale@gmail.com",
        "time": "Tue May 05 10:41:52 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue May 05 10:41:52 2026 -0700"
      },
      "message": "chore(release): Version bump after release v0.1.11 (#579)\n\nVersion bump after release v0.1.11"
    },
    {
      "commit": "b4525d2bb0e1c0190d3d1bdf46711ee5dd1c4889",
      "tree": "3189ed7bd5a40451245dfe4390259d34e1d50445",
      "parents": [
        "71d177b8b7309de45deec02d17557ffe8aed52b4"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Thu Apr 30 12:11:14 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Apr 30 12:11:14 2026 -0700"
      },
      "message": "fix(dataclass): collect py_class fields from plain bases (#575)\n\n## Summary\n\nFixes `@py_class` field collection when a decorated class inherits\nannotated fields through one or more non-`@py_class` Python bases.\n\nPreviously, `typing.get_type_hints(cls)` resolved inherited annotations,\nbut the field collector only iterated over annotations declared directly\non `cls`. A class such as `Add(BaseBinOp)` where `BaseBinOp` is a plain\nPython subclass of a registered FFI class would therefore register no\n`lhs` / `rhs` fields on `Add`, and construction failed with an\nunexpected keyword argument error.\n\nThis PR updates the collector to walk the current class MRO until the\nnearest registered FFI parent, collecting annotations from\nnon-registered Python bases as fields owned by the new type. The nearest\nregistered parent remains the TypeInfo boundary, so fields already\nregistered on `@py_class` ancestors are not duplicated.\n\nThe field merge now follows the review feedback from Gemini:\n\n- collection iterates owner classes from base to child,\n- `KW_ONLY` state is carried across the flattened non-FFI owner list,\n- fields are merged by name in insertion-order-preserving dictionaries,\nso an override keeps the original field position while adopting the\nmost-derived metadata.\n\nIt also updates class attribute installation to only preserve attributes\ndefined directly on the registered class. This prevents inherited plain\nPython defaults or `Field` sentinels from shadowing the reflected\nproperty descriptor installed for the child type.\n\n## Behavioral Impact\n\n- `@py_class` subclasses now accept fields declared on unregistered\nPython parents between the child and its registered FFI ancestor.\n- Field metadata from those plain parents is preserved, including\n`ClassVar`, `KW_ONLY`, and `init\u003dFalse` behavior.\n- Python multiple inheritance through non-FFI bases is covered as long\nas the class has a single registered FFI lineage.\n- More-derived field overrides preserve the first field position while\nreplacing metadata and type information.\n- No public API or ABI is added or removed.\n\n## Tests\n\n- `python -m ruff check tests/python/test_dataclass_py_class.py\npython/tvm_ffi/dataclasses/py_class.py python/tvm_ffi/registry.py`\n- `ty check tests/python/test_dataclass_py_class.py`\n- `python -m pytest tests/python/test_dataclass_py_class.py -q`\n- `python -m pytest tests/python/test_dataclass_enum.py\ntests/python/test_dataclass_common.py\ntests/python/test_dataclass_c_class.py\ntests/python/test_dataclass_init.py -q`\n\nAll checks passed locally.\n\nNote: the standalone `bug.py` reproducer is not present in this checkout\nafter the latest amendment, but the same construction path is covered by\n`test_collects_fields_from_non_py_class_parent`."
    },
    {
      "commit": "71d177b8b7309de45deec02d17557ffe8aed52b4",
      "tree": "990063a9b0553e1c9adac2f76be2827177354dd1",
      "parents": [
        "3c35034fd1026011736e19a4e0e1ed0f22058c42"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Thu Apr 30 10:28:27 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri May 01 01:28:27 2026 +0800"
      },
      "message": "chore(doc): Temp workaround missing pytorch docs (#577)\n\nWill switch back once https://docs.pytorch.org/docs/stable/objects.inv\nbecomes available again."
    },
    {
      "commit": "3c35034fd1026011736e19a4e0e1ed0f22058c42",
      "tree": "2a9bb3f1400cd417dbf55cd12cdc87dcb89dd4df",
      "parents": [
        "e472871900b80f1407d6880d103be4a874bb4084"
      ],
      "author": {
        "name": "Yaxing Cai",
        "email": "caiyaxing666@gmail.com",
        "time": "Mon Apr 27 03:31:02 2026 +0800"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Apr 26 15:31:02 2026 -0400"
      },
      "message": "[OrcJIT] Arena JITLinkMemoryManager with GOTPCRELX fix (Linux) (#527)\n\n## Summary\n\nAdds an arena-based `JITLinkMemoryManager` that eliminates\nscattered-mmap relocation overflow in LLVM ORC JIT under ASLR / VA\npressure ([LLVM\n#173269](https://github.com/llvm/llvm-project/issues/173269)), plus a\nworkaround for an x86_64 JITLink GOTPCRELX relaxation bug. Linux only;\nother platforms fall back to the default `InProcessMemoryManager`.\n\n### Arena memory manager (`orcjit_arena_mm.{h,cc}`)\n\n- Pre-reserves one contiguous VA region via `mmap(PROT_NONE |\nMAP_NORESERVE)` at session startup and bump-allocates from it,\nguaranteeing all JIT allocations stay within PC-relative range (±2 GB\nx86_64, ±4 GB AArch64).\n- Default capacity: 4 GB (x86_64) / 8 GB (AArch64). On reservation\nfailure (RLIMIT_AS, containers) the constructor halves down to a 256 MB\nfloor.\n- **Dual-pool split.** Arena is partitioned at a 2 MB-aligned midpoint\ninto a non-exec pool (`r--`/`rw-`) and an exec pool (`r-x`). Exec\nsegments pack tightly into whole 2 MB pages for contiguous r-x layout\nand TLB-friendly huge-page promotion. Both pools are capped so\ncross-pool Delta32 fixups always resolve inside ±2 GB.\n- **Slab commit with THP.** Physical pages are committed in 2 MB slabs,\nmatching Linux huge page size. `madvise(MADV_HUGEPAGE)` on the full\nreservation lets the kernel promote fully-faulted slabs to single TLB\nentries.\n- **Overflow sections.** Known large absolute-only sections\n(`.nv_fatbin`) are routed to separate `mmap()` allocations outside the\narena. Guarded by a two-phase check: name-based candidate selection,\nthen edge validation that disqualifies any section targeted by a\nPC-relative reference.\n- **Segment-lifetime handling.** `Finalize`-lifetime pages are freed at\nthe end of `finalize()`; `Standard`-lifetime pages remain until\n`deallocate()`. Free list coalesces adjacent blocks for reuse.\n- Decommit is deliberately a no-op: `ELFNixPlatform` deinitializers can\nstill reference freed allocations during teardown. Physical pages return\nto the free list instead; all memory is reclaimed by `munmap` in the\narena destructor.\n\n### GOTPCRELX fix plugin (`orcjit_session.cc`)\n\n- Works around LLVM JITLink\u0027s `optimizeGOTAndStubAccesses()` relaxing\n`call *foo@GOTPCREL(%rip)` → `addr32 call foo` but tagging the edge as\nabsolute `Pointer32`. On non-PIE executables with symbols in the low 4\nGB, this produces a garbage displacement → SIGSEGV during ORC-runtime\nteardown.\n- `GOTPCRELXFixPlugin` runs as a `PreFixupPass` after relaxation and\neither converts to `BranchPCRel32` when the displacement fits, or\nreverts the relaxation (restores `ff 15`/`ff 25` opcodes, retargets the\nedge to the GOT entry with `PCRel32`).\n\n### Configuration\n\n`ExecutionSession(arena_size\u003d...)` / `arena_size_bytes` C++ arg: `0` \u003d\narch default, `\u003e0` \u003d custom size, `\u003c0` \u003d disable arena. Linux-only;\nignored on macOS/Windows where the arena is compiled out.\n\n### Tests (`tests/test_arena.py`)\n\n8 arena tests across C/C++/GCC/PIE variants:\n\n- `test_arena_colocation` — objects stay within a small window.\n- `test_arena_keeps_objects_close` — scatter baseline under VA blocker\nwith arena enabled.\n- `test_arena_hidden_symbol_with_blocker` — ADRP/PC32 cross-object calls\nresolve under VA pressure.\n- `test_large_data_section` — 4 MB `.nv_fatbin` loads inside arena when\nreferences are absolute.\n- `test_overflow_section_outside_arena` — `.nv_fatbin` routed to\nseparate mmap, confirmed via address gap.\n- `test_dso_handle_relocation_after_failed_materialization` —\n`__dso_handle` resolves after prior sessions leaked slabs.\n- `test_dso_handle_delta32_with_arena` / `_overflow_without_arena` —\n`-fpie` GCC objects under 3 GB VA blocker: with arena → passes; without\narena → Delta32 overflow.\n\nAll tests use a 16 MB arena and 256 MB–3 GB VA blockers, safe for CI.\n\n## Test plan\n\n- [x] All orcjit tests pass locally on Linux x86_64 and aarch64\n- [ ] CI green on Linux x86_64, Linux aarch64, macOS arm64, Windows\nAMD64\n- [x] Non-Linux platforms unaffected (arena compiled out under `#ifdef\n__linux__`)\n\n---------\n\nCo-authored-by: Yaxing Cai \u003cyaxingc@gb-nvl-054-compute02.nvidia.com\u003e"
    },
    {
      "commit": "e472871900b80f1407d6880d103be4a874bb4084",
      "tree": "fe52e3bde90b6008b29b35d3640aff36a91668ab",
      "parents": [
        "899c5fb22cb41bed9e48ed259c6717d01757eb4d"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sun Apr 26 13:42:40 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Apr 27 01:42:40 2026 +0800"
      },
      "message": "[FIX] Handle kTVMFFIRawStr / kTVMFFIByteArrayPtr in callback args path (#573)\n\n## Summary\n\n- **Bug**: When C++ invokes a Python callback with non-owning `RawStr`\nor `ByteArrayPtr` arg shapes, `TVMFFICyCallbackArgSetterFactory` (in\n`pycallback.pxi`) raised `ValueError` for both type indices, crashing\nthe callback immediately.\n\n- **Fix**: Add two new Cython setter functions —\n`TVMFFIPyCallbackArgSetterRawStr_` and\n`TVMFFIPyCallbackArgSetterByteArrayPtr_` — and register them in\n`TVMFFICyCallbackArgSetterFactory`. Each setter converts the non-owning\nC-side view to a Python `str` (UTF-8 decode) or `bytes` (memcopy) before\nreturning. Both non-owning views remain valid for the callback\u0027s\nduration, so there is no dangling-pointer concern.\n\n- **Why not change `make_ret`**: The return-value path (C-side\n`ffi::Function` invocation) never carries `kTVMFFIRawStr` /\n`kTVMFFIByteArrayPtr` because C++ normalises to owned variants\n(`ffi::String` / `ffi::Bytes`) before returning. The existing `raise\nValueError` arms in `make_ret` remain correct guards against an\nimpossible return-side type, exactly like the `kTVMFFIObjectRValueRef`\narm.\n\n- **Test**: One regression test in `tests/python/test_function.py`\n(`test_callback_rawstr_and_bytearrayptr_args`) uses\n`tvm_ffi.cpp.load_inline` to build a C++ shim with two trampolines:\n- `invoke_with_raw_str(callback)` — passes a C-string literal as `const\nchar*`, which `TypeTraits\u003cconst char*\u003e::CopyToAnyView` packs as\n`kTVMFFIRawStr` (with `v_c_str`).\n- `invoke_with_byte_array_ptr(callback)` — passes a stack\n`TVMFFIByteArray*`, which `TypeTraits\u003cTVMFFIByteArray*\u003e::CopyToAnyView`\npacks as `kTVMFFIByteArrayPtr` (with `v_ptr`).\nBoth paths are exercised in a single test body; the callback asserts it\nreceives a `str` / `bytes` with the expected content.\n\n## Files changed\n\n- `python/tvm_ffi/cython/pycallback.pxi` — two new setter functions +\nfactory registration\n- `tests/python/test_function.py` — one regression test + `import\ntvm_ffi.cpp`\n\n## Test plan\n\n- [ ] `uv run pytest -vvs tests/python/test_function.py` — 20 passed\n(was 19)\n- [ ] `uv run pytest tests/python` — 2303 passed, 5 skipped, 2 xfailed\n(3 pre-existing ROCm failures unrelated to this change)\n- [ ] `pre-commit run --files python/tvm_ffi/cython/pycallback.pxi\ntests/python/test_function.py` — all hooks passed"
    },
    {
      "commit": "899c5fb22cb41bed9e48ed259c6717d01757eb4d",
      "tree": "58014a13913af7b5007449bcb47337d1a47ce182",
      "parents": [
        "bc64ba3e981ae44a542ed4e7590320b15e530f57"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sat Apr 25 13:02:35 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Apr 26 01:02:35 2026 +0800"
      },
      "message": "[REFACTOR] libinfo: add extra_lib_paths parameter for foreign-caller support (#570)\n\n## Summary\n\n`tvm_ffi.libinfo._find_library_by_basename(package, target_name)`,\n`load_lib_ctypes(...)`, and `load_lib_module(...)` now accept an\noptional\n`extra_lib_paths: list[Path] | None` parameter. Caller-supplied dirs\ntake\nprecedence over the existing `_rel_top_directory()` /\n`_dev_top_directory()`\nfallback. Self-call behavior unchanged.\n\nOn miss, the `RuntimeError` now lists every directory searched so\ndebugging\nis one error message away.\n\n## API\n\n```python\ndef load_lib_ctypes(\n    package: str,\n    target_name: str,\n    mode: str,\n    extra_lib_paths: list[Path] | None \u003d None,\n) -\u003e ctypes.CDLL: ...\n\ndef load_lib_module(\n    package: str,\n    target_name: str,\n    keep_module_alive: bool \u003d True,\n    extra_lib_paths: list[Path] | None \u003d None,\n) -\u003e Module: ...\n```\n\n`list[Path]` over `Sequence[Path | str]` — callers naturally produce\n`Path`\nobjects from `__file__`; single canonical type, no internal\nnormalization,\nfuture widening is non-breaking."
    },
    {
      "commit": "bc64ba3e981ae44a542ed4e7590320b15e530f57",
      "tree": "43bcf4d21dd71d07984c219bb065fdb4baad974e",
      "parents": [
        "96edb9a8fd0c474b311234b174719dda20230419"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Sat Apr 25 12:57:01 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Apr 26 00:57:01 2026 +0800"
      },
      "message": "[REFACTOR] Optimized Python callback path via TVMFFIPyCallbackArgSetter (#569)\n\nThis PR optimizes python callback specifically when the arguments expect\na torch.Tensor class.\n\n`tvm_ffi.convert_func(pyfunc, tensor_cls\u003dNone)` is provided. If\n`tensor_cls`\nis provided, the closure threads its `__dlpack_c_exchange_api__` capsule\ninto the callback so tensor args are delivered as `tensor_cls` instances\n(e.g., `torch.Tensor`) directly from the C-level setter — no per-arg\nPython-level conversion without python torch dlpack conversion overhead\n\nExample:\n\n```python\nimport torch\nimport tvm_ffi\n\ndef callback(a: torch.Tensor, b: torch.Tensor, c: torch.Tensor) -\u003e None:\n    # a, b, c arrive as torch.Tensor, converted in C via the closure\u0027s\n    # DLPack exchange API — no from_dlpack() needed inside the callback.\n    torch.add(a, b, out\u003dc)\n\nf \u003d tvm_ffi.convert_func(callback, tensor_cls\u003dtorch.Tensor)\n```\n\n| Variant                               | Per-call |\n|---------------------------------------|----------|\n| pycallback[tensor_cls\u003dtorch.Tensor]   | ~640 ns  |\n| pycallback+from_dlpack (explicit x3)  | ~9.1 us  |"
    },
    {
      "commit": "96edb9a8fd0c474b311234b174719dda20230419",
      "tree": "153fac40d4c0f9e85a3948df6e088d8293d36e51",
      "parents": [
        "02a344dbe6df51b8506194a2f56bea482274f90a"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Fri Apr 24 02:20:59 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Apr 24 02:20:59 2026 -0700"
      },
      "message": "feat(enum): add payload enum compatibility behavior (#568)\n\nTL;DR:\n- Make `IntEnum` and `StrEnum` variants behave like their raw payloads\nfor common Python enum operations while preserving FFI singleton\nidentity through same_as.\n\nExamples:\n- `Priority.low.name \u003d\u003d \"low\"` and `repr(Priority.low) \u003d\u003d\n\"Priority.low\"`.\n- `Priority.low \u003d\u003d 10`, `str(Priority.low) \u003d\u003d \"10\"`, and\n`hash(Priority.low) \u003d\u003d hash(10)`.\n- `Priority(10).same_as(Priority.low)` and\n`Priority(\"low\").same_as(Priority.low)`.\n- `Opcode(\"+\").same_as(Opcode.add)` and\n`Opcode(\"add\").same_as(Opcode.add)`.\n\nDetails:\n- Install payload-only instance dunders after `py_class`/`c_class`\ngeneration so payload semantics override generated object defaults\nwithout clobbering explicit user methods.\n- Gate payload behavior on `__ffi_enum_payload_value_type__` so plain\nEnum does not interpret arbitrary class-body values as public payloads.\n- Keep single-argument member lookup in `_EnumMeta.__call__` for\nexisting variants, raw payloads, and names.\n- Document why these methods are dynamically installed and what\nidentity/equality contract they preserve.\n- Add enum tests covering `name`, `repr`, `str`, `equality`, `hashing`,\nand construction from payload/name."
    },
    {
      "commit": "02a344dbe6df51b8506194a2f56bea482274f90a",
      "tree": "3f1dbb98848588f73c57a75bd5042efa5f273274",
      "parents": [
        "281f7e114fc46d262ccb57c18d19c7ef7b0a018c"
      ],
      "author": {
        "name": "Kathryn (Jinqi) Chen",
        "email": "65606304+Kathryn-cat@users.noreply.github.com",
        "time": "Fri Apr 24 00:08:39 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Apr 24 00:08:39 2026 -0700"
      },
      "message": "feat: Added typed method registration for py_class (#567)\n\n## Add type method registration on py_class\n\nfeat(dataclasses): add @method decorator for FFI TypeMethod registration\n\nCloses the gap where `@py_class`-decorated Python classes couldn\u0027t\nexpose user-defined methods to the FFI reflection table. Trait\nreferences like `$method:NAME` in `__ffi_ir_traits__` now resolve\ncleanly against Python-defined methods, on parity with C++-defined\n`refl::ObjectDef\u003cT\u003e().def(\"name\", ...)`.\n\n## Architecture\n\n- `tvm_ffi.method` decorator stamps `fn.__ffi_method__ \u003d True` on the\n  decorated function (unwraps `staticmethod` to `__func__` so both\n  `@method @staticmethod` and `@staticmethod @method` work).\n- `_collect_py_methods` in `py_class.py` widens beyond the existing\n  `_FFI_RECOGNIZED_METHODS` allowlist: it now also picks up any\n  callable in `cls.__dict__` carrying the `__ffi_method__` marker\n  via `_is_method_marked`. The allowlist still routes TypeAttrColumn\n  dunders (`__ffi_repr__`, `__ffi_ir_traits__`, etc.) through\n  `TVMFFITypeRegisterAttr` unchanged.\n- Marked methods register through the existing TypeMethod path\n  (`TVMFFITypeRegisterMethod`) — same machinery the C++ side uses.\n  The C++ printer\u0027s `FindMethod` (`pyast_trait_print.cc:130-148`) walks\n  `info-\u003emethods[]` and discovers these entries identically to\n  C++-defined methods, including ancestor-walking for inheritance.\n- `_validate_method_name` rejects `@method` decoration on:\n  - `__ffi_*` reserved prefix (would double-register as TypeAttrColumn),\n  - Python protocol dunders (`__len__`, `__iter__`, etc. — reserved\n    for Python semantics),\n  - `@classmethod` (the `cls` first arg breaks the packed-call\n    convention; raises at decoration time).\n- Identity-typed: `@method` returns the original function unchanged\n  (no wrapping); IDE / type-checker sees the method\u0027s signature\n  unmodified.\n\n## Public Interfaces\n\n- `tvm_ffi.method` (re-exported from `tvm_ffi.dataclasses`)\n\n## Behavioral Changes\n\nNone for existing classes. Only NEW `@method`-decorated callables land\nin `TVMFFITypeInfo.methods[]`.\n\n## Tests\n\n- `tests/python/test_typed_method.py` (new, 13 tests): registration\n  shape, FFI Function callability, validation errors.\n- `tests/python/test_ir_traits.py` (5 new tests): end-to-end via\n`pyast.to_python()` against `$method:` refs in\n`AssignTraits.text_printer_post`,\n  `"
    },
    {
      "commit": "281f7e114fc46d262ccb57c18d19c7ef7b0a018c",
      "tree": "7a1bcc6936f37075ab5b4072559adf1ed1226f22",
      "parents": [
        "d70c905d16d16a93fedd7417e1500aaf11dfb530"
      ],
      "author": {
        "name": "Yaoyao Ding",
        "email": "dingyaoyao.cs@gmail.com",
        "time": "Fri Apr 24 01:20:07 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Apr 23 22:20:07 2026 -0700"
      },
      "message": "doc: clarify structural_eq semantics and py_class eq/hash interaction (#566)\n\nRework the const-tree section in docs/concepts/structural_eq_hash.rst:\nthe \"Why not use it everywhere?\" example was bad — the drawn trees had\ndifferent pointers for their `+` nodes, so the const-tree pointer\nshortcut would never have fired. Replaced it with a shared-subtree\nscenario under `map_free_vars\u003dTrue` that actually exercises the bug, and\nexpanded \"When is this safe?\" with a third condition (interning payoff)\nplus a rule of thumb for choosing between `tree` and `const-tree`.\n\nExpand the `\"var\"` section to document that non-ignored fields on a var\ntype (e.g. a type annotation) are compared on first encounter but\nsubsequent occurrences short-circuit through the bijective mapping —\ni.e. the mapping is sticky.\n\nClarify the py_class docstring so readers understand that\n`structural_eq` is independent of `eq` / `unsafe_hash`: the default\n`__eq__` / `__hash__` remain pointer-based (inherited from `Object`),\nwhile `structural_equal` / `structural_hash` are driven separately by\nthe kind metadata registered in C++.\n\n---------\n\nCo-authored-by: Claude Opus 4.7 (1M context) \u003cnoreply@anthropic.com\u003e\nCo-authored-by: gemini-code-assist[bot] \u003c176961590+gemini-code-assist[bot]@users.noreply.github.com\u003e"
    },
    {
      "commit": "d70c905d16d16a93fedd7417e1500aaf11dfb530",
      "tree": "3393cf672018b2da068d6ba44194d8922347aea2",
      "parents": [
        "09e7216697307aaf454c041a9d527bd88f9986ee"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Tue Apr 21 09:35:03 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Apr 21 09:35:03 2026 -0700"
      },
      "message": "refactor(enum)!: hide identity fields, add IntEnum/StrEnum, consolidate accessors (#564)\n\n## Summary\n\nThis PR completes the enum identity-vs-payload separation: it hides the\nintrinsic `_value` / `_name` fields, introduces `IntEnum` / `StrEnum`\npayload bases, consolidates the class-level entry accessors into a\nsingle `all_entries()` iterator, and adds a payload-aware fast path in\nthe Cython type converter so `py_class` fields typed as a payload-enum\naccept raw `int` / `str` values.\n\n## Architecture\n\n- **Rename `EnumObj::value` / `name` to `_value` / `_name`** across the\nC++ layout, reflection schema (`ObjectDef\u003cEnumObj\u003e::def_ro`), repr\nprinter, and `reflection::EnumDef`. The leading underscore frees the\npublic `value` symbol for user payload fields while keeping the dense\nordinal and declaration-key as the canonical variant identity.\n- **Add `IntEnum` / `StrEnum` base classes** in\n`tvm_ffi.dataclasses.enum` that reserve a declared `value: int` (resp.\n`str`) payload field via `_prepare_payload_enum_subclass`. The helper\ninjects or validates the `value` annotation *before*\n`Enum.__init_subclass__` runs, so reflection sees the payload as a\nfirst-class declared field rather than an extensible attribute, and\nstamps `__ffi_enum_payload_value_type__` onto the class for downstream\ndispatch.\n- **Tighten `py_class` parent-info lookup** to fall back to\n`base.__tvm_ffi_type_info__` when the core registry lookup misses, so\nPython subclasses descending through `IntEnum` / `StrEnum` register with\nthe correct parent type info.\n- **Consolidate class-level entry accessors** into a single\n`all_entries()` iterator backed by `_ordered_entries`. The `by_name` /\n`by_value` descriptors and the older `entries()` method are removed;\n`_EnumMeta.__iter__` / `__len__` and the public accessor now share one\ncanonical ordering path.\n- **Accept payload-literal variant declarations** on `IntEnum` /\n`StrEnum` (`red \u003d 10`, `add \u003d \"+\"`) as sugar for `entry(value\u003d...)`.\n`_collect_entry_declarations` treats bare assignments on payload enums\nas `_EnumEntry` values, and invalid payload types surface as a\n`TypeError` via the new `_instantiate_entry` error-normalizing wrapper.\n- **Payload-aware Cython dispatch**: new `_tc_convert_int_enum` /\n`_tc_convert_str_enum` inspect the registered target class\u0027s MRO at\nschema-build time and, at call time, coerce raw `int` / `str` payloads\ninto the matching variant via `all_entries()`. The object-passthrough\nand pack/convert fallback are preserved by factoring the marshaled path\ninto `_tc_convert_object_marshaled`.\n\n## Public Interfaces (BREAKING)\n\n- **C++ ABI break**: `EnumObj::value` / `EnumObj::name` no longer exist;\nconsumers must read `EnumObj::_value` / `EnumObj::_name`.\n- **Python API break**: on plain `Enum` subclasses, `instance.value` /\n`instance.name` are no longer surfaced (they raise `AttributeError`).\nUse `_value` / `_name` for the intrinsic ordinal and key, or migrate to\n`IntEnum` / `StrEnum` to obtain a user-visible `value` payload.\n- **Python API break**: `Enum.entries()` is renamed to\n`Enum.all_entries()`; `Enum.by_name` and `Enum.by_value` class\nproperties are removed. Replace `Cls.entries()` with\n`Cls.all_entries()`, `Cls.by_value` with `list(Cls.all_entries())`, and\n`Cls.by_name` with `{e._name: e for e in Cls.all_entries()}`.\n- **New exports**: `tvm_ffi.dataclasses.IntEnum` and\n`tvm_ffi.dataclasses.StrEnum` (added to `__all__`).\n- `entry(...)` now rejects `_value\u003d` / `_name\u003d` kwargs (previously\n`value\u003d` / `name\u003d`).\n- `IntEnum` / `StrEnum` subclasses additionally accept `red \u003d 10` / `add\n\u003d \"+\"` as sugar for `entry(value\u003d...)`.\n- `py_class` fields typed as `IntEnum` / `StrEnum` subclasses now accept\nraw `int` / `str` payloads at construction and assignment; the converter\nresolves them to the singleton variant and rejects unknown payloads with\nthe usual `expected \u003cType\u003e` error.\n\n## Behavioral Changes\n\n- Reading `.value` / `.name` on a plain `Enum` variant raises\n`AttributeError`.\n- Repr still produces `\u003ctype_key\u003e.\u003c_name\u003e` (wire-identical).\n- `iter(EnumCls)` and `len(EnumCls)` now route through\n`_ordered_entries` instead of the removed `by_value` descriptor;\nobservable ordering is unchanged (dense ordinal order).\n- Constructing an enum subclass with an invalid literal payload (e.g.,\n`class Bad(IntEnum): nope \u003d \"x\"`) now raises `TypeError` with a\n`\u003cCls\u003e.\u003cname\u003e: invalid enum entry: ...` prefix via `_instantiate_entry`,\nrather than leaking the raw converter error.\n- `py_class` field assignments of the form `inst.priority \u003d 20` (where\n`priority: Priority` is an `IntEnum`) now succeed, binding to the\ncorresponding enum variant.\n- **Python 3.8/3.9 compatibility**: `_prepare_payload_enum_subclass`\nuses `_own_annotations(cls)` rather than `getattr(cls,\n\"__annotations__\", {})`. The previous lookup followed MRO when the\nsubclass had no annotations of its own and pulled in the parent `Enum`\u0027s\n`_value` / `_name`, which then re-registered those fields on the\nsubclass and produced `ValueError: duplicate parameter name: \u0027_value\u0027`\nwhen constructing the `inspect.Signature` for `__init__`. Python 3.10+\nwas unaffected because the interpreter always materializes an empty\n`__annotations__` dict in every class body.\n\n## Docs\n\n- Doxygen and Python docstrings updated in-place in\n`include/tvm/ffi/enum.h`, `include/tvm/ffi/reflection/enum_def.h`,\n`include/tvm/ffi/reflection/accessor.h`, and\n`python/tvm_ffi/dataclasses/enum.py`.\n- No doc-site page referenced the old public `EnumObj::value` / `name`\nor the removed `entries()` / `by_name` / `by_value` accessors (verified\nvia `rg` over `docs/`), so no further changes in `docs/` were required.\n\n## Test plan\n\n- [x] `uv pip install --force-reinstall --verbose -e .` rebuild after\nCython changes in `pyclass_type_converter.pxi`.\n- [x] `uv run pytest -vvs tests/python/test_dataclass_enum.py\ntests/python/test_dataclass_py_class.py\ntests/python/test_type_converter.py` — 1008 passed, 2 xfailed.\n- [x] New tests:\n- `test_int_enum_payload_literal_sugar`,\n`test_str_enum_payload_literal_sugar`,\n`test_payload_literal_sugar_preserves_annotated_field_defaults`,\n`test_int_enum_payload_literal_sugar_rejects_invalid_payload`,\n`test_str_enum_payload_literal_sugar_rejects_invalid_payload`.\n- `test_all_entries_iteration_order`,\n`test_all_entries_indexed_by_ordinal` (replacing the removed\n`test_by_name_is_live_dict` / `test_by_value_indexed_by_ordinal`).\n- `test_public_value_and_name_are_hidden` (identity-hidden assertion on\nplain `Enum`).\n- `test_int_enum_payload_value` / `test_str_enum_payload_value`\n(end-to-end payload).\n- `TestPayloadEnums` group in `test_type_converter.py` covering int/str\npayload conversion, object passthrough, and rejection of unknown\npayloads.\n- `test_payload_enum_fields_end_to_end` in `test_dataclass_py_class.py`\ncovering construction, assignment, and error behavior for `IntEnum` /\n`StrEnum`-typed `py_class` fields.\n- [x] Python 3.8 MRO-lookup behavior reproduced on CPython 3.8.20 and\nthe `_own_annotations` fix validated against it.\n- [ ] CI C++ tests for `refl::EnumDef` (Linux x86_64/aarch64, macOS\narm64, Windows) — not rerun locally; relying on CI to exercise the\nrenamed `_value` / `_name` compile path.\n- [ ] CI Rust job — no local Rust coverage for downstream `EnumObj`\nfield consumers.\n- [ ] Cross-language (C++-backed) `IntEnum` / `StrEnum` payload coercion\nis not specifically exercised; existing `test_cxx_backed_*` cases cover\nthe object-passthrough path, and the new literal-sugar path targets\npure-Python subclasses.\n\n## Migration\n\n- Replace `enum_instance.value` / `.name` with `._value` / `._name`,\n**or** switch the base class to `IntEnum` / `StrEnum` to keep a\nuser-visible `value` field.\n- Replace `entry(value\u003d..., name\u003d...)` with `entry(_value\u003d...,\n_name\u003d...)`, or drop them (both are auto-assigned).\n- Replace `Cls.entries()` with `Cls.all_entries()`.\n- Replace `Cls.by_value` with `list(Cls.all_entries())`.\n- Replace `Cls.by_name` with `{e._name: e for e in Cls.all_entries()}`."
    },
    {
      "commit": "09e7216697307aaf454c041a9d527bd88f9986ee",
      "tree": "20268c1a81387d081a82b43876773b4cad3d6bde",
      "parents": [
        "68b06e9e45a1daa0180994aab1d7ed2695e257b1"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Tue Apr 21 09:34:52 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Apr 21 09:34:52 2026 -0700"
      },
      "message": "fix(container): align sequence equality and contains (#560)"
    },
    {
      "commit": "68b06e9e45a1daa0180994aab1d7ed2695e257b1",
      "tree": "ca3c6ca6d484351a455eea55a545d864ca960676",
      "parents": [
        "24054b47bd013398e2c7bacb312f2d5e21059d50"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Mon Apr 20 19:50:46 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Apr 20 19:50:46 2026 -0700"
      },
      "message": "fix(dataclass): distinguish containers from dataclasses (#557)"
    },
    {
      "commit": "24054b47bd013398e2c7bacb312f2d5e21059d50",
      "tree": "017c08356e2294d1c5251ea1932266e70a02e32d",
      "parents": [
        "7055626763b3e76c60842274286e10bde0f464ad"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Mon Apr 20 18:41:22 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Apr 20 18:41:22 2026 -0400"
      },
      "message": "[FEAT] Enhance map_dataclass_to_tuple with JIT unpack_dataclass_to_tuple (#563)\n\nThis PR introduces an optimized unpack_dataclass_to_tuple util and\nreplaces `dataclasses.astuple` in `map_dataclass_to_tuple`, a\nJIT-compiled per-class unpacker that brings 5-11x speedup and does not\ndeep-copy leaf values.\n\nNot deep-copying leaf is important for runtime use-cases, when dataclass\nfields contain tensor objects or other large resources that must not be\ncopied -- leaf values are passed through by reference, not duplicated.\n\n## Design\n\n`unpack_dataclass_to_tuple(x)` recursively converts dataclass instances\nto tuples via JIT-compiled inline attribute access:\n\n- `_extract_dataclass_to_tuple_schema(cls)` -- inspect type annotations\n- `_validate_dataclass_to_tuple_schema(schema)` -- codegen security\n- `_compile_dataclass_to_tuple_schema(prefix, schema)` -- inline code\n\nCached per-thread (TLS) for thread safety. Conservative field\nclassification: only marks as leaf when certain (known primitives,\ncontainers of known primitives). Unknown types use dynamic dispatch.\n\n## Performance (vs dataclasses.astuple)\n\n| Case              | unpack | astuple | speedup |\n|-------------------|--------|---------|---------|\n| Config (2 flat)   | 144 ns |  769 ns |   5.3x  |\n| Nested (int + dc) | 152 ns | 1386 ns |   9.1x  |\n| Wide (5 flat)     | 170 ns | 1268 ns |   7.5x  |\n| Deep (2 levels)   | 200 ns | 2305 ns |  11.5x  |\n| WithAny (dynamic) | 254 ns | 1644 ns |   6.5x  |"
    },
    {
      "commit": "7055626763b3e76c60842274286e10bde0f464ad",
      "tree": "95f64a0c687a848d96db81aa95e66cb16da20687",
      "parents": [
        "fc6cf8a0596b6cc1a7f3b453d18bab3c60310622"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Mon Apr 20 12:40:52 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Apr 20 12:40:52 2026 -0700"
      },
      "message": "fix(dataclass): resolve cross-module forward refs (#559)"
    },
    {
      "commit": "fc6cf8a0596b6cc1a7f3b453d18bab3c60310622",
      "tree": "48e1bac32f5fa2e2fb6383f60589d8ab252a26f2",
      "parents": [
        "6066f605558ec4bbc9d477e46894439edef60022"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Mon Apr 20 12:29:20 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Apr 20 12:29:20 2026 -0700"
      },
      "message": "fix(enum): add class iteration and len (#558)"
    },
    {
      "commit": "6066f605558ec4bbc9d477e46894439edef60022",
      "tree": "8dd5d85162ac3713241bf26cb9a56598c8bf918c",
      "parents": [
        "9c4f59878ba11950eaae22fa50d2d6a3c9322043"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Sat Apr 18 14:41:32 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Apr 18 14:41:32 2026 -0700"
      },
      "message": "feat(core): Introduce Attribute-Carrying Language-Agnostic Enums (#554)\n\nRFC: https://github.com/apache/tvm-ffi/issues/553\n\nAdd first-class cross-language enum support to TVM-FFI. An enum is a\nregistered Object type whose instances are named, frozen singletons —\nthe same model as `tvm::Op`, generalised into an `Enum` base class\nusable from Python and C++ and converging on a single shared registry\nper `type_key`.\n\n## At a glance\n\n### Python\n\n```python\nfrom __future__ import annotations\n\nfrom typing import ClassVar\n\nfrom tvm_ffi.dataclasses import Enum, auto, entry\n\n\n# Pure-Python enum — fresh type_key, no C++ involvement.\nclass Priority(Enum, type_key\u003d\"my.Priority\"):\n    low \u003d auto()\n    medium \u003d auto()\n    high \u003d auto()\n\n\n# Attribute-carrying enum.\nclass Activation(Enum, type_key\u003d\"nn.Activation\"):\n    output_zero: bool\n    is_monotonic: bool\n\n    relu: ClassVar[Activation] \u003d entry(output_zero\u003dTrue, is_monotonic\u003dTrue)\n    gelu: ClassVar[Activation] \u003d entry(output_zero\u003dFalse, is_monotonic\u003dFalse)\n    silu: ClassVar[Activation] \u003d entry(output_zero\u003dFalse, is_monotonic\u003dTrue)\n\n\n# Python class binding C++-registered entries.\nclass Variant(Enum, type_key\u003d\"testing.TestEnumVariant\"):\n    Alpha: ClassVar[Variant]   # bound to the C++-registered \"Alpha\"\n    Beta:  ClassVar[Variant]   # bound to the C++-registered \"Beta\"\n\n\nassert Activation.relu.value \u003d\u003d 0          # auto-assigned ordinal\nassert Activation.relu.name \u003d\u003d \"relu\"      # auto-populated\nassert Activation.relu.output_zero is True # user field\nassert Activation.get(\"relu\") is Activation.relu\n\n# Extensible per-variant attributes, writable from anywhere.\ncost \u003d Activation.def_attr(\"cost\", default\u003d0)\ncost[Activation.relu] \u003d 1\ncost[Activation.gelu] \u003d 4\nassert cost[Activation.silu] \u003d\u003d 0          # default — silu was never assigned\nassert Activation.silu not in cost         # distinguishes default-hit vs. set\n```\n\n### C++\n\n```cpp\n#include \u003ctvm/ffi/enum.h\u003e\n#include \u003ctvm/ffi/reflection/enum_def.h\u003e\n\nclass ActivationObj : public tvm::ffi::EnumObj {\n public:\n  bool output_zero;\n  bool is_monotonic;\n  TVM_FFI_DECLARE_OBJECT_INFO_FINAL(\"nn.Activation\", ActivationObj, tvm::ffi::EnumObj);\n};\n\nTVM_FFI_STATIC_INIT_BLOCK() {\n  namespace refl \u003d tvm::ffi::reflection;\n  refl::ObjectDef\u003cActivationObj\u003e(refl::init(false))\n      .def_ro(\"output_zero\", \u0026ActivationObj::output_zero)\n      .def_ro(\"is_monotonic\", \u0026ActivationObj::is_monotonic);\n\n  refl::EnumDef\u003cActivationObj\u003e(\"relu\")\n      .set_attr(\"output_zero\", true)\n      .set_attr(\"is_monotonic\", true);\n  refl::EnumDef\u003cActivationObj\u003e(\"gelu\")\n      .set_attr(\"output_zero\", false)\n      .set_attr(\"is_monotonic\", false);\n}\n```\n\nThe Python and C++ halves write to the same two `type_index`-keyed\nTypeAttr columns, so a Python subclass that binds\n`type_key\u003d\"nn.Activation\"` sees every C++-registered entry, and any\nlater `auto()`/`entry(...)` from Python becomes visible to C++ readers\nof the same columns. Entries cross FFI as ordinary `ObjectRef`s — no\nwire-format work.\n\n## Design\n\n- Enum instances are `EnumObj` subclasses. Each carries a dense\nauto-assigned `int64_t value` (0-indexed per class, declaration-order\nordinal) and a `String name`. Both are populated at registration;\nneither is user-supplied.\n- Two per-class TypeAttr columns, shared across all call sites:\n- `__ffi_enum_entries__` — `Dict\u003cString, Enum\u003e` mapping instance name →\nfrozen singleton.\n- `__ffi_enum_attrs__` — `Dict\u003cString, List\u003cAny\u003e\u003e` mapping attribute\nname → ordinal-indexed list.\n- **Register-once-then-mutate.** Each column is registered exactly once\nvia `TVMFFITypeRegisterAttr`; every subsequent writer fetches the live\ncontainer with `TVMFFIGetTypeAttrColumn` and mutates it in place.\nDistributed registration across TUs or Python modules converges on one\nset of containers.\n- **Python variants** are declared in one of four shapes, processed in\n`Enum.__init_subclass__`:\n1. `name: ClassVar[Cls] \u003d entry(**kwargs)` — registers a Python-side\nentry and forwards kwargs to `__init__`.\n2. `name \u003d entry(**kwargs)` (no annotation) — same as 1, for\nattribute-carrying enums where `ClassVar` is noise.\n3. `name \u003d auto()` (or `name: ClassVar[Cls] \u003d auto()`) — registers a\nvariant with no extra fields; the preferred form for simple enums.\n4. Bare `name: ClassVar[Cls]` — binds to a C++-registered entry of the\nsame name, or registers a blank Python entry if none exists.\n\nWithin one class body, bare `ClassVar` binders resolve first (annotation\norder), then sentinel assignments (class-body order); auto-ordinals\nfollow that combined order. Mixing all four forms on a single class is\nsupported.\n- **Auto-detected backend.** `Enum.__init_subclass__(type_key\u003d...)`\nroutes the subclass through `@c_class` if the type is already registered\nin the FFI type system, otherwise through `@py_class`. There is no\nseparate `py_enum`/`c_enum` opt-in.\n- **Integer literals are rejected** on the RHS. The auto-ordinal policy\nowns `value`, so `ok \u003d 0` and `entry(0)` would either duplicate or\nconflict with the auto-ordinal. `auto()` is the intended replacement.\n`entry(value\u003d...)` / `entry(name\u003d...)` raise `TypeError` at class-body\ntime.\n\n## New public interfaces\n\n### C++ headers\n\n- `include/tvm/ffi/enum.h` — `EnumObj` (`int64_t value`, `String name`,\nboth `def_ro`-reflected) and `Enum` (nullable `ObjectRef` wrapper),\nregistered under type key `ffi.Enum`. Plus two column-name constants\n`kEnumEntriesAttrName` (\u003d `\"__ffi_enum_entries__\"`) and\n`kEnumAttrsAttrName` (\u003d `\"__ffi_enum_attrs__\"`).\n- `include/tvm/ffi/reflection/enum_def.h` —\n`refl::EnumDef\u003cT\u003e(\"name\").set_attr(\"key\", value)...`. Each call\nallocates a fresh ordinal, constructs the instance, and writes it into\nthe per-class registry. Duplicate names for the same `T` raise\n`RuntimeError`. Exposes `.instance()` / `.ordinal()` for tests /\nadvanced callers.\n- `include/tvm/ffi/tvm_ffi.h` transitively includes both new headers.\n\n### Python surface (`tvm_ffi.dataclasses`)\n\n- `Enum` — base class, decorated\n`@dataclass_transform(field_specifiers\u003d(Field, field, entry, auto))` so\ntype checkers recognise `entry()` / `auto()` as dataclass-field\nspecifiers.\n- `entry(**kwargs)`, `auto()` — variant-declaration sentinels.\n- `EnumAttrMap` — view over the shared `__ffi_enum_attrs__` column;\n`__getitem__` / `__setitem__` / `__contains__` / `get(default\u003d...)`.\n- Per-subclass surface: `Cls.get(name)`, `Cls.entries()`,\n`Cls.def_attr(name, *, default\u003d...)`, and three live class-level\nproperties `Cls.by_name` (`Dict[str, Enum]`), `Cls.by_value`\n(`List[Enum]` indexed by ordinal), `Cls.attr_dict` (`Dict[str,\nList[Any]]`). The class-level properties are backed by an internal\n`_ClassProperty` descriptor so they work without a metaclass.\n\n## Other user-visible changes\n\n- **`TVMFFITypeRegisterAttr` rejects duplicate `(type_index, attr_name)`\nwrites.** Reverses a previously relaxed \"silent overwrite\" behaviour.\nThe enforced invariant is load-bearing for the register-once-then-mutate\nprotocol; the error message points callers at that protocol.\n- **Default repr for `EnumObj` subclasses** is `\u003ctype_key\u003e.\u003cname\u003e`\ninstead of the generic `type_key(field1\u003d..., field2\u003d...)` form. Rendered\nby `ReprPrinter` after the `__ffi_repr__` hook check, so explicit\noverrides still take precedence.\n- **Built-in sentinels `MISSING` / `KWARGS`** now render as `\u003cMISSING\u003e`\n/ `\u003cKWARGS\u003e` via pointer-identity dispatch, replacing the generic\n`ffi.Object` fallback.\n- **C++ test-support type `testing.TestEnumVariant`** (in\n`src/ffi/testing/testing.cc`) now extends `EnumObj` and registers\n`Alpha` / `Beta` entries with a `code` attribute via `refl::EnumDef`.\nThis is the canonical end-to-end demonstration of the builder and is\nexercised by the Python test suite.\n\n## Testing\n\n- `uv run pytest tests/python/test_dataclass_enum.py -q` — 38/38\npassing. Covers all four declaration forms, auto-ordinal assignment,\nfrozen-singleton identity, rejection of `entry(value\u003d...)` /\n`entry(name\u003d...)`, `get` / `entries` / `by_name` / `by_value` /\n`attr_dict`, `def_attr` round-trips through the unified column, direct\nTypeAttr verification, the C++-backed happy path against\n`testing.TestEnumVariant`, mixed C++/Python entry registration, and the\nrepr / sentinel behaviour.\n- `uv run pytest tests/python -q` — 2246 passed, 16 skipped, 3 xfailed.\nNo regressions.\n- `pre-commit run --all-files` — clean.\n\nC++ GoogleTest and Rust suites were not re-run; the enum builder is\nexercised end-to-end from the Python tests against\n`testing.TestEnumVariant`, and no Rust bindings were touched."
    },
    {
      "commit": "9c4f59878ba11950eaae22fa50d2d6a3c9322043",
      "tree": "bedcf24f5e99e62eb740b106fc7e5e9bd9340ddb",
      "parents": [
        "b8d810459a983f9c822a31b313348ea94c9af44c"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Fri Apr 17 18:02:40 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Apr 17 18:02:40 2026 -0700"
      },
      "message": "feat(dataclass): add asdict, astuple, and match_args support (#556)\n\n## Summary\n\nAdds three stdlib-parity features to `tvm_ffi.dataclasses`:\n\n1. **`asdict(obj, *, dict_factory\u003ddict)`** — recursively converts a\n`@py_class` / `@c_class` instance to a plain Python `dict`. FFI\ncontainers (`Array`, `List`) recurse into `list`; (`Map`, `Dict`)\nrecurse into `dict`, yielding JSON-ready output.\n2. **`astuple(obj, *, tuple_factory\u003dtuple)`** — the tuple analogue of\n`asdict`, with the same recursion rules.\n3. **`match_args: bool \u003d True`** parameter on `@py_class` and `@c_class`\n— sets `cls.__match_args__` to the tuple of positional `__init__` field\nnames (`init\u003dTrue and not kw_only`), enabling Python 3.10+ `match`\nstatements. Skipped when the class body already defines\n`__match_args__`.\n\nSemantics follow CPython\u0027s `dataclasses` module: `asdict`/`astuple`\nraise `TypeError` for types and non-dataclass values; kw-only fields\n(via `field(kw_only\u003dTrue)`, decorator-level `kw_only\u003dTrue`, or the\n`KW_ONLY` sentinel) are excluded from `__match_args__`.\n\n## Design notes\n\n- `_is_ffi_dataclass_instance` filters FFI container instances (`Array`,\n`List`, `Map`, `Dict`) from FFI dataclass instances — both share\n`__tvm_ffi_type_info__`, so the container isinstance-check runs first\nduring recursion.\n- `_set_match_args` walks the `TypeInfo.parent_type_info` chain in\nparent-first order, matching the order of the auto-generated `__init__`\nsignature.\n- Recursion uses an `_ATOMIC_TYPES` frozenset (mirroring stdlib\n`dataclasses._ATOMIC_TYPES`) for the fast path on immutable leaves.\n\n## Test plan\n\n- [x] `uv run pytest tests/python/` — 2184 passed, 38 skipped, 3 xfailed\n- [x] `pre-commit run --files \u003ctouched files\u003e` — all hooks pass (ruff,\nty, format)\n- [x] New coverage in `tests/python/test_dataclass_common.py`:\n- `TestAsdict` (15 tests): basic, nested, inheritance, FFI\nArray/List/Map/Dict recursion, `dict_factory`, result independence,\nerror paths\n- `TestAstuple` (10 tests): basic, nested, recursion, `tuple_factory`,\nerror paths\n- `TestMatchArgs` (11 tests): defaults, `init\u003dFalse`, kw_only (field /\ndecorator / `KW_ONLY` sentinel), inheritance order, `match_args\u003dFalse`\nopt-out, user-defined `__match_args__` override, c_class basic and\ninheritance"
    },
    {
      "commit": "b8d810459a983f9c822a31b313348ea94c9af44c",
      "tree": "fe23c337ea71eac51e9a4232096eb04cb3dc6861",
      "parents": [
        "02e9928a356c2d448e17d9fbdd37738cddceb0a1"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Fri Apr 17 12:21:25 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Apr 17 12:21:25 2026 -0700"
      },
      "message": "feat(dataclass): Introduce more utility methods in `tvm_ffi.dataclasses.*` (#555)\n\n## Summary\n\nThis PR introduces:\n- `tvm_ffi.dataclasses.fields` similar to\n[dataclasses.fields](https://docs.python.org/3/library/dataclasses.html#dataclasses.fields)\n- `tvm_ffi.dataclasses.replace` similar to\n[dataclasses.replace](https://docs.python.org/3/library/dataclasses.html#dataclasses.replace)\n- `tvm_ffi.dataclasses.is_dataclass` similar to\n[dataclasses.is_dataclass](https://docs.python.org/3/library/dataclasses.html#dataclasses.is_dataclass)\n- `tvm_ffi.Object.id_` similar to\n[id](https://docs.python.org/3/library/functions.html#id)\n- `tvm_ffi.Object.is_` similar to Python\u0027s `is` keyword\n\n## Test plan\n- [x] `uv run pytest tests/python` — 2148 passed, 38 skipped, 3 xfailed\n- [x] `pre-commit run --all-files` — 27 hooks passed\n- [x] New tests for every new attribute/flag and for `id_`/`is_` alias\nparity\n- [ ] CI lint + C++ unit tests + Rust tests"
    },
    {
      "commit": "02e9928a356c2d448e17d9fbdd37738cddceb0a1",
      "tree": "6ef2d510529888dda8f4040d79e762ccf2f60b7e",
      "parents": [
        "2f1a16a4d41fb05e0fc313ed20a3df35a9a9bca8"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Tue Apr 14 22:12:26 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Apr 14 22:12:26 2026 -0700"
      },
      "message": "fix(py_class): remove __ffi_init_inplace__ to fix memory leak (#551)\n\n## Summary\n\n- **Fix memory leak** in `@py_class`: the custom `__new__` override\nallocated a spurious C++ object via `__ffi_new__` whenever a py_class\ninstance was returned from C++, which was then orphaned when\n`make_ret_object` overwrote `chandle` with the actual return value.\n- **Remove `__ffi_init_inplace__`** entirely — both the C++\n`MakeInitInplace` function, its registration, and the `kInitInplace`\nconstant.\n- **Unify `c_class` and `py_class`** auto-generated `__init__` to both\nuse `self.__init_handle_by_constructor__(ffi_init, *args)`, differing\nonly in guard logic: py_class uses a `chandle !\u003d 0` guard (no-op when\nalready allocated), c_class uses a `type_info` identity guard\n(`TypeError` from subclass).\n- **Remove the custom `__new__` override** — no more spurious allocation\non the `make_ret` path.\n- **Wrap user-defined `__init__`** on py_class with a `chandle \u003d\u003d 0`\nguard that pre-allocates via `__ffi_new__` before user code runs; use\n`functools.wraps` to preserve metadata.\n\n### Files changed\n\n| File | Change |\n|------|--------|\n| `python/tvm_ffi/_dunder.py` | Core redesign: removed `inplace` param,\nadded `py_class_mode`, removed `__new__` override, added user-init\nwrapping with `functools.wraps` |\n| `python/tvm_ffi/registry.py` | Removed `inplace\u003dFalse` kwarg from\n`_make_init` call |\n| `include/tvm/ffi/reflection/accessor.h` | Removed `kInitInplace`\nconstant |\n| `include/tvm/ffi/reflection/registry.h` | Updated comments (removed\n`__ffi_init_inplace__` references) |\n| `src/ffi/extra/dataclass.cc` | Removed `MakeInitInplace()`, its\nregistration, `EnsureTypeAttrColumn` call |\n| `python/tvm_ffi/dataclasses/py_class.py` | Updated comment |\n| `tests/python/test_dataclass_init.py` | Removed `TestInitInplace`\nclass (5 tests) |\n| `tests/python/test_dataclass_py_class.py` | Added 8 new tests in\n`TestPyClassNoLeak` |\n\n## Test plan\n\n- [x] All 27 pre-commit linters pass\n- [x] All 2103 Python tests pass (2095 existing + 8 new)\n- [x] All 349 C++ tests pass\n- [x] Memory leak validation: 20k construct+deepcopy cycles with no leak"
    },
    {
      "commit": "2f1a16a4d41fb05e0fc313ed20a3df35a9a9bca8",
      "tree": "fc7d74abdbfc25c1d038093cef96c48f5e13ee8a",
      "parents": [
        "528ce7cef74e3233d7082dbe017f44c7891fb372"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Tue Apr 14 14:59:28 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Apr 14 14:59:28 2026 -0700"
      },
      "message": "feat(string): add String::Split, EscapedStringPy, and rename EscapeString (#550)\n\n## Summary\n\n- Rename `EscapeString` to `EscapeStringJSON` to clarify its\nJSON-specific escaping semantics (RFC 8259). A deprecated `EscapeString`\nalias is retained for backward compatibility.\n- Add `EscapedStringPy` for Python-style string escaping that handles\nANSI escape sequences, UTF-8 multibyte characters, and standard C escape\nsequences (`\\n`, `\\t`, `\\r`, `\\\\`, `\\\"`).\n- Add `String::Split(char delim)` utility method that returns\n`std::vector\u003cstd::string_view\u003e` segments.\n- Update all internal call sites (`function.h`, `registry.h`,\n`dataclass.cc`, `json_writer.cc`) to use the new `EscapeStringJSON`\nname.\n- `ReprPrinter` now uses `EscapedStringPy` instead of `EscapeStringJSON`\nfor proper Python-style `__repr__` output.\n\n## Motivation\n\nThe existing `EscapeString` function was JSON-specific but its name did\nnot convey this. This rename makes intent explicit. The new\n`EscapedStringPy` function supports Python-style repr output needed for\nerror messages and debugging. `String::Split` is a common utility needed\nacross the codebase.\n\n## Changes\n\n| File | Change |\n|------|--------|\n| `include/tvm/ffi/string.h` | Rename `EscapeString` -\u003e\n`EscapeStringJSON`, add deprecated alias, add `EscapedStringPy`, add\n`String::Split` |\n| `include/tvm/ffi/string.h` | Cast to `unsigned char` before\n`std::isdigit` to avoid UB; use `\\x1b` for ANSI escapes; validate UTF-8\ncontinuation bytes |\n| `include/tvm/ffi/function.h` | Update call site to `EscapeStringJSON`\n|\n| `include/tvm/ffi/reflection/registry.h` | Update call site to\n`EscapeStringJSON` |\n| `src/ffi/extra/dataclass.cc` | `ReprPrinter` uses `EscapedStringPy`\nfor Python-style repr output |\n| `src/ffi/extra/json_writer.cc` | Update call site to\n`EscapeStringJSON` |\n| `tests/cpp/test_string.cc` | Add 7 test cases for `Split`,\n`EscapeStringJSON`, `EscapedStringPy` (basic, control chars, ANSI,\nUTF-8, malformed UTF-8) |\n\n## Test plan\n\n- [x] All 47 C++ string tests pass\n- [x] `String::Split` tested with edge cases (empty, boundaries,\nconsecutive delimiters)\n- [x] `EscapeStringJSON` tested with special chars, backslash, quotes,\ncontrol chars\n- [x] `EscapedStringPy` tested: basic ASCII, control chars, ANSI\nsequences, valid UTF-8 (2/3/4-byte), malformed UTF-8\n- [x] Existing Python tests pass (deprecated alias preserves\ncompatibility)"
    },
    {
      "commit": "528ce7cef74e3233d7082dbe017f44c7891fb372",
      "tree": "048abf357ce742efbf20fd0d1fcfd2455748c75f",
      "parents": [
        "f26ff61eea2f7c3c9fe195ebb81873f30b33a81a"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Tue Apr 14 13:41:37 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Apr 14 13:41:37 2026 -0700"
      },
      "message": "feat(dataclass): emit __ffi_init__ stubs, harden field registration, and support Python 3.14 (#549)\n\n## Summary\n\n- **Stub generation**: emit `__ffi_init__` stubs alongside `__init__`\nfor all reflected types, sourced from either TypeMethod (explicit\n`refl::init\u003c\u003e`) or synthesized from field metadata (auto-generated\ninit).\n- **Field registration hardening**: reject duplicate field names within\na type (C++ `ICHECK` + Python `assert`) and warn when child fields\nshadow ancestor fields, in both C++ (`object.cc`) and Cython\n(`type_info.pxi`).\n- **Python 3.14 compatibility (PEP 749)**: use `getattr(cls,\n\"__annotations__\", {})` on 3.14+ where annotations are lazily evaluated\nvia `__annotate__`, falling back to `cls.__dict__` on older versions.\n- **Additional fixes**: null-guard `DecRefObjectHandle`,\n`TVM_FFI_UNREACHABLE()` in `creator.h`, `signed char` cast fix for\nclang-tidy, MSVC `/bigobj`, allow non-callable type attrs in\n`_collect_py_methods`, consolidate test skip markers, update stubgen\ndocs."
    },
    {
      "commit": "f26ff61eea2f7c3c9fe195ebb81873f30b33a81a",
      "tree": "bef582087e8bc7a6717e3007bd0a376535c3617f",
      "parents": [
        "b7c30ea6e8264f8189c0ab94f2ebb04e955812ad"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Tue Apr 14 04:32:27 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Apr 14 07:32:27 2026 -0400"
      },
      "message": "perf(container): use iterator lookup instead of exception handling in Map/Dict (#548)\n\n## Summary\n\n- Replace `try { n-\u003eat(k); } catch (...)` with `n-\u003efind(k)` + iterator\ncheck in `ffi.MapGetItemOrMissing` and `ffi.DictGetItemOrMissing`\n- Avoids the overhead of throwing and catching exceptions on every\nmissing-key lookup\n- No behavioral change: both paths return `GetMissingObject()` for\nabsent keys\n\nCloses #547\n\n## Test plan\n\n- [x] `uv run pytest -vvs tests/python` -- 2088 passed, 38 skipped, 3\nxfailed (no new failures)\n- [x] Pre-commit hooks pass (clang-format, ASF header, file types, etc.)"
    },
    {
      "commit": "b7c30ea6e8264f8189c0ab94f2ebb04e955812ad",
      "tree": "b91a16097df67c5d052e46f1423044a79d42698a",
      "parents": [
        "e809f98099790f870184aa69537ffccce78b5a86"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Mon Apr 13 19:31:28 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Apr 14 10:31:28 2026 +0800"
      },
      "message": "fix(init): register __ffi_init__ as TypeMethod and use MISSING sentinel (#546)\n\n## Summary\n\n- **C++ `def(init\u003c\u003e)`**: Register `__ffi_init__` as TypeMethod\n(preserving `type_schema` metadata for stub generation), then mirror to\nTypeAttrColumn for backward compatibility. Aligns\n`ObjectDef::def(init\u003c\u003e)` with `OverloadObjectDef::def(init\u003c\u003e)` which\nalready did this.\n- **Python `__ffi_init__` lookup**: Prefer TypeMethod over\nTypeAttrColumn when resolving `__ffi_init__` in `_install_init` and\n`_install_dataclass_dunders`.\n- **Python `_install_ffi_init_attr`**: New helper that installs\n`__ffi_init__` as an instance method with a type-owner guard, preventing\nsubclass misuse.\n- **MISSING sentinel**: Use `core.MISSING` (not a private `__SENTINEL`)\nfor default parameter values in auto-generated `__init__` signatures,\nand skip MISSING kwargs instead of forwarding them to C++.\n\n## Test plan\n\n- [x] 23 new regression tests added to `test_dataclass_init.py`\n  - TypeMethod registration for `def(init\u003c\u003e)` classes\n  - `__ffi_init__` as callable instance method\n  - Type-owner guard preventing subclass misuse\n  - `core.MISSING` sentinel for default parameters\n  - Dual TypeMethod/TypeAttrColumn availability\n- [x] All 2095 existing Python tests pass\n- [x] All pre-commit hooks pass (ruff, ty, clang-format)\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-authored-by: Claude Opus 4.6 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "e809f98099790f870184aa69537ffccce78b5a86",
      "tree": "1ba66e15edbc155dcea6a52f200a9d3552c858ef",
      "parents": [
        "ef511d41402fed19927f663da90315b18db20cc8"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Mon Apr 13 10:56:54 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Apr 13 10:56:54 2026 -0700"
      },
      "message": "feat(container): add structural `__eq__`/`__ne__`/`__hash__` to Array, List, Map, Dict (#545)\n\n## Summary\n\n- Add structural `__eq__`, `__ne__`, and `__hash__` methods to the four\ncontainer classes (`Array`, `List`, `Map`, `Dict`) in\n`python/tvm_ffi/container.py`\n- Delegates to existing `RecursiveEq` and `RecursiveHash` C++ FFI\nfunctions — the same infrastructure used by `_install_dataclass_dunders`\nin `_dunder.py` for `@c_class`/`@py_class`\n- Returns `NotImplemented` for unrelated types so Python\u0027s default\ncomparison fallback applies\n- `Shape`, `String`, and `Bytes` are unchanged (already inherit correct\nbehavior from `tuple`, `str`, `bytes`)\n\n## Breaking Change\n\nCode that relied on identity-based equality for containers will now see\nstructural equality instead. For example, `Array([1, 2]) \u003d\u003d Array([1,\n2])` now returns `True` (previously `False`). Two container objects with\nthe same contents now compare equal and produce the same hash.\n\n## Test Plan\n\n- [x] 17 new tests added in `tests/python/test_container.py` covering:\n  - Structural equality and inequality for all four container types\n  - Empty containers\n  - Nested containers (Array of Arrays)\n  - `NotImplemented` return for unrelated types (plain list, dict, str)\n  - Hash consistency (equal objects produce equal hashes)\n  - Usability as set members and dict keys\n- [x] Full Python test suite passes: 2072 passed, 38 skipped, 3 xfailed\n- [x] All pre-commit hooks pass (ruff, ty check, etc.)"
    },
    {
      "commit": "ef511d41402fed19927f663da90315b18db20cc8",
      "tree": "d895aa88c078041a702e6bc6baf2c7ef75c921cb",
      "parents": [
        "e10f635544b48ad52b13085369a55b38bc88b7be"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Mon Apr 13 01:00:22 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Apr 13 01:00:22 2026 -0700"
      },
      "message": "feat(py_class): support `frozen\u003dTrue` for immutable instances (#542)\n\n## Summary\n\n- Add `frozen` parameter to `@py_class()` decorator and `field()`\nfunction, mirroring Python\u0027s `dataclasses.dataclass(frozen\u003dTrue)`\nsemantics.\n- **Class-level frozen**: `@py_class(frozen\u003dTrue)` installs\n`__setattr__`/`__delattr__` guards raising `FrozenInstanceError`. Frozen\nclasses auto-get `__hash__` (safely hashable).\n- **Field-level frozen**: `field(frozen\u003dTrue)` sets\n`TypeField.frozen\u003dTrue` (`fset\u003dNone`), independent of class-level\nfrozen.\n- `__replace__` (`copy.replace`) uses direct `FieldSetter` for\n`py_class` (bypasses both frozen mechanisms) while `c_class` respects\nC++ readonly fields via `object.__setattr__`.\n\n## Test plan\n\n- [x] 101 new tests in `tests/python/test_dataclass_frozen.py` covering:\n  - Class-level frozen basic behavior and error messages\n  - Field-level frozen (individual field override)\n  - Inheritance (frozen parent + mutable child, mixed)\n  - Interactions with `eq`, `hash`, `order`, `copy`, `replace`\n  - `object.__setattr__` escape hatch\n  - `FrozenInstanceError` is `AttributeError` subclass\n- [x] Full test suite: 2105 passed, 0 failed, 38 skipped, 3 xfailed"
    },
    {
      "commit": "e10f635544b48ad52b13085369a55b38bc88b7be",
      "tree": "fa875af0196406ef027d3d312f93a2b85432bfdf",
      "parents": [
        "cc1346a573d02a3836ad73d8e7850e14cb8d7eb0"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Mon Apr 13 00:38:46 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Apr 13 00:38:46 2026 -0700"
      },
      "message": "fix(c_class): restore `__init__` installation from `__ffi_init__` TypeAttrColumn (#543)\n\n## Summary\n\n- Fixes a regression from cc1346a5 (#541) where `register_object`\nstopped installing `__init__` from the C++ `__ffi_init__`\nTypeAttrColumn, causing segfaults when constructing objects like\n`IntPair` in `examples/python_packaging/`\n- Adds `_install_init(cls, type_info)` in `registry.py` that restores\nthe invariant: if `__ffi_init__` exists, install `__init__` via\n`_dunder._make_init`; if no reflection and no user `__init__`, install a\nTypeError guard instead of allowing segfaults\n- For `PyNativeObject` subclasses (e.g., `Shape`) that use `__new__`,\nthe helper is a no-op\n\n## Test plan\n\n- [x] `uv run pytest -vvs tests/python/` -- 2004 passed, 38 skipped, 3\nxfailed\n- [x] `examples/python_packaging/run_example.py` constructs `IntPair`\ncorrectly\n- [x] Pre-commit hooks all pass"
    },
    {
      "commit": "cc1346a573d02a3836ad73d8e7850e14cb8d7eb0",
      "tree": "5bc2bbf5c967b0d203ffc3f17e9c12bbd03ddc87",
      "parents": [
        "be9a8274623252b48ac252961f5968255bf51114"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Sun Apr 12 16:42:52 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Apr 12 16:42:52 2026 -0700"
      },
      "message": "refactor(dataclass): consolidate dunder method installation into _dunder.py (#541)\n\n## Summary\n\n- Consolidate\n`__new__`/`__init__`/`__repr__`/eq/ne/ordering/hash/copy/deepcopy/replace\ninstallation for `@c_class` and `@py_class` into a single `_dunder.py`\nmodule with `_install_dataclass_dunders` as the entry point\n- Introduce `__ffi_new__` and `__ffi_init__`/`__ffi_init_inplace__` as\nuniversal `TypeAttrColumns`, replacing ad-hoc `__c_ffi_init__` renaming\nand `auto_init` metadata\n- Remove `init.h`; consolidate C++ registration into `dataclass.cc`;\neliminate `ffi.NewEmpty`, `ffi.MakeFFINew`, `ffi.RegisterAutoInit`\n- `py_class` uses `__ffi_init_inplace__` (object pre-allocated by\n`__new__`), `c_class` uses `__ffi_init__` (via\n`__init_handle_by_constructor__`)\n- Use factory pattern for copy/deepcopy/replace with install-time\nresolution\n- Add `KW_ONLY` regression tests"
    },
    {
      "commit": "be9a8274623252b48ac252961f5968255bf51114",
      "tree": "dacb106c135cae5d1a2dd0b9aaf441df640f33e3",
      "parents": [
        "aed51c05236be1835065c0ce4bd86dc54c3b934c"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Sun Apr 12 13:05:04 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Apr 12 13:05:04 2026 -0700"
      },
      "message": "fix(py_class): support `tvm_ffi.dtype` and `tvm_ffi.Device` as field type annotations (#540)\n\n## Summary\n\n- `TypeSchema.from_annotation()` in the Cython layer only recognized the\nC-level `DataType`/`Device` cdef classes for dtype/device annotations\n(`annotation is DataType`). The public Python wrapper classes —\n`tvm_ffi.dtype` (`class dtype(str)` in `_dtype.py`) and `tvm_ffi.Device`\n— are distinct types, so using them as `@py_class` field type\nannotations raised `TypeError: Cannot convert \u003cclass \u0027...\u0027\u003e to\nTypeSchema`.\n- The fix extends the identity checks to also match the Python wrapper\nclasses via the existing `_CLASS_DTYPE` / `_CLASS_DEVICE` module-level\nsentinels.\n- Added 6 regression tests covering dtype fields, Device fields,\ncombined usage, setter mutation, and `Optional` variants.\n\n## Test plan\n\n- [x] `uv run pytest -vvs tests/python/test_dataclass_py_class.py` — all\n342 tests pass (including 6 new `TestDtypeDeviceFields` tests)\n- [ ] CI: lint, C++ tests, full Python test suite, Rust tests\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)"
    },
    {
      "commit": "aed51c05236be1835065c0ce4bd86dc54c3b934c",
      "tree": "fc101cafbba4a4d1bee64fd71692b66842e04713",
      "parents": [
        "2b59825e87a70dac521490802306e461024cc4d1"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Sun Apr 12 13:04:48 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Apr 12 13:04:48 2026 -0700"
      },
      "message": "fix(py_class): propagate parent total_size through empty intermediate classes (#539)\n\n## Summary\n\n- **Bug**: In Python-defined type hierarchies, when an intermediate\nparent class\nhad no own fields (e.g., `GrandParent(x, y) -\u003e Parent(pass) -\u003e Child(a,\nb)`),\n`TypeInfo.total_size` fell back to `sizeof(TVMFFIObject)` (~24 bytes)\nfor the\nempty parent, ignoring inherited fields. This caused child field offsets\nto\noverlap with grandparent field offsets, leading to silent data\ncorruption on\n  read/write.\n- **Fix**: Replace the `sizeof(TVMFFIObject)` floor with\n`self.parent_type_info.total_size` in `TypeInfo.total_size`, ensuring\ninherited\nfield space propagates correctly through arbitrarily deep empty parents.\nAdded a\nguard that `parent_type_info` must be present and an assertion that the\nbase size\n  is at least `sizeof(TVMFFIObject)`.\n- **Tests**: Added 6 regression tests in `TestFieldInheritance` covering\noffset\ncorrectness, total_size propagation, non-overlapping child offsets,\ntwo-level\nempty intermediate parents, mutation aliasing, and the `@py_class`\ndecorator path.\n\n## Architecture\n\n- **Changed file**: `python/tvm_ffi/cython/type_info.pxi` —\n`TypeInfo.total_size`\n  property body (6 lines replaced with 6 lines; decorator unchanged).\n- **Root cause**: The old code initialized `end \u003d sizeof(TVMFFIObject)`\nand only\niterated over `self.fields` (the type\u0027s own fields). An empty\nintermediate class\nhas no own fields, so it returned a total_size equal to just the object\nheader,\n  erasing all inherited field space.\n- **Fix mechanism**: `end \u003d self.parent_type_info.total_size` inherits\nthe parent\u0027s\nfull layout (including transitively inherited fields), then `max(end,\nf.offset + f.size)`\n  extends it for any own fields.\n\n## Behavioral Changes\n\n- Before: `Child.a` at offset 24 overlapping `GrandParent.x` at offset\n24 when\n  `Parent` had no own fields. Reading `obj.x` returned `obj.a`\u0027s value.\n- After: `Child.a` starts at or after `Parent.total_size` (which equals\n  `GrandParent.total_size`), so no field overlap occurs.\n\n## Test Plan\n\n- [x] `uv run pytest -vvs\ntests/python/test_dataclass_py_class.py::TestFieldInheritance` -- all\ntests pass (8 existing + 6 new)\n- [x] All pre-commit hooks pass"
    },
    {
      "commit": "2b59825e87a70dac521490802306e461024cc4d1",
      "tree": "337bb409696b1c591f6cc8c948523a925e56987a",
      "parents": [
        "f41dbfd648f5f2be82986aebcd3201f10c1d2974"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Fri Apr 10 11:26:30 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Apr 10 11:26:30 2026 -0700"
      },
      "message": "fix(py_class): support `super().__init__()` in `init\u003dFalse` subclasses (#532)\n\n## Summary\n\n- Fix segfault when `@py_class(init\u003dFalse)` subclasses use\n`super().__init__()` followed by field assignment\n- Add `ffi.NewEmpty` C++ function to allocate zero-initialized objects\nby type index\n- Detect super-init-from-subclass pattern in `_make_init()` and\npre-allocate instead of dispatching to `__ffi_init__`\n\n## Motivation\n\nThe common Python pattern of defining a custom `__init__` that calls\n`super().__init__()` then sets fields crashes when used with\n`@py_class(init\u003dFalse)`:\n\n```python\n@py_class(init\u003dFalse)\nclass PointerType(Node):\n    element_type: Object\n\n    def __init__(self, element_type):\n        super().__init__()       # parent\u0027s auto-init dispatches to child\u0027s C++ ctor → crash\n        self.element_type \u003d element_type\n```\n\nThe parent\u0027s auto-generated `__init__` forwards to `__ffi_init__` using\nthe child type\u0027s C++ constructor, which expects field arguments that\nwere not provided.\n\n## Design\n\n**C++ side** (`src/ffi/extra/dataclass.cc`): Register\n`ffi.NewEmpty(type_index) -\u003e ObjectRef` that allocates a\nzero-initialized object via `CreateEmptyObject`. The calloc\u0027d state is\nvalid: `None` for `Any`/`ObjectRef` fields, `0` for scalars.\n\n**Python side** (`python/tvm_ffi/registry.py`):\n- `_ffi_alloc_empty(obj)`: Calls `ffi.NewEmpty` to allocate an empty FFI\nobject for `type(obj)` and moves the handle into `obj`. No-op if already\nallocated.\n- `_is_super_init_from_subclass(self)`: Compares\n`type(self).__tvm_ffi_type_info__` identity against the declaring\nclass\u0027s `type_info`. Returns `True` only for registered `@py_class`\nsubclasses — undecorated subclasses inherit the parent\u0027s `type_info` so\nthe identity check correctly filters them out.\n- Both `_make_init` code paths (with/without `__post_init__`) intercept\nthe no-args super-init-from-subclass call and allocate an empty object\ninstead of dispatching to `__ffi_init__`.\n\n## Test plan\n\n- [x] `uv run pytest -vvs\ntests/python/test_dataclass_py_class.py::TestSuperInitPattern` — 12\ntests pass\n- [x] `uv run pytest -vvs tests/python/` — 1970 passed, 38 skipped, 3\nxfailed, 0 failures\n\nTests cover: basic super-init, deep hierarchy\n(Node→BaseType→PointerType), calloc defaults, intermediate custom/auto\ninits, normal init unaffected, non-py_class subclass error handling,\nisinstance checks, field overwrite, copy/deepcopy, and\ndirect-from-Object inheritance."
    },
    {
      "commit": "f41dbfd648f5f2be82986aebcd3201f10c1d2974",
      "tree": "b81984d4c1d789eefda858c8f7c444e6d8254c8f",
      "parents": [
        "059f8af3436b4b1fc629ba6d2c87f6be72513aeb"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Fri Apr 10 08:41:17 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Apr 10 08:41:17 2026 -0700"
      },
      "message": "feat(c_class): warn when reflected fields lack Python type annotations (#531)\n\n## Summary\n\n- When a `@c_class`-decorated class has C++-reflected fields without\ncorresponding Python type annotations, the decorator now emits a\n`UserWarning` at class-definition time listing the missing names.\n- This gives library authors an early, actionable signal that IDE\nsupport (autocompletion, type checking, hover docs) is degraded for\nthose fields.\n- The warning is non-breaking: filterable via the standard `warnings`\nmodule and does not alter runtime semantics.\n\n## Changes\n\n- **`python/tvm_ffi/registry.py`** — new\n`_warn_missing_field_annotations` helper\n- **`python/tvm_ffi/dataclasses/c_class.py`** — call the helper after\n`register_object()` succeeds\n- **`tests/python/test_dataclass_c_class.py`** — 5 new test cases\n(all/no/partial annotations, zero fields, derived class)\n\n## Test plan\n\n- [x] `uv run pytest -vvs tests/python/test_dataclass_c_class.py` passes\nlocally\n- [ ] CI green on all platforms"
    },
    {
      "commit": "059f8af3436b4b1fc629ba6d2c87f6be72513aeb",
      "tree": "cfa27753b9153f5207ea483927321ab40c1be5a5",
      "parents": [
        "3d33014ba11fb5556fcd10a9cc11a540dd799443"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Fri Apr 10 06:03:30 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Apr 10 09:03:30 2026 -0400"
      },
      "message": "fix(cython): Segfault in free-threaded Py_DecRef Cleanup (#529)\n\nFree-threaded CPython still requires an attached PyThreadState before\nusing the Python C API. tvm-ffi skipped that setup under\nPy_GIL_DISABLED, so native cleanup paths could call Py_DecRef without\nthread state and crash.\n\nAlways attach thread state around native decref paths, and add a\nfree-threaded regression test that drops the last ref from a\ndetached-thread-state region. The test is skipped on non-free- threaded\nbuilds and runs in the existing 3.14t CI job."
    },
    {
      "commit": "3d33014ba11fb5556fcd10a9cc11a540dd799443",
      "tree": "479b709360280b0af37b67a1d93043c0b6239dbc",
      "parents": [
        "1a305b63b17f41695c97d379dff96c6169cdb209"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Wed Apr 08 00:23:40 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Apr 08 15:23:40 2026 +0800"
      },
      "message": "build(deps): replace cmake version exclusion with uv exclude-newer (#526)\n\nRemove the `cmake\\!\u003d4.3.1` version pin from dev dependencies and instead\nadd a `[tool.uv] exclude-newer \u003d \"14 days\"` setting. This prevents\ninstalling any package released within the last 14 days, which is a more\ngeneral and maintainable approach to avoiding freshly-released broken\npackages across the entire dependency tree.\n\n- Architecture: No changes.\n- Public Interfaces: No changes.\n- UI/UX: No changes.\n- Behavioral Changes: `uv` will now exclude packages newer than 14 days\nfor all resolution, not just cmake. The cmake-specific version exclusion\nis removed.\n- Docs: No changes needed (build config only).\n- Tests: No changes needed (config-only change).\n- Untested Edge Cases: The `exclude-newer` directive is relative (\"14\ndays\"), so resolution results will vary by the date `uv` is invoked. CI\nreproducibility depends on lockfile presence."
    },
    {
      "commit": "1a305b63b17f41695c97d379dff96c6169cdb209",
      "tree": "ce838318369bbc7409a8cb0a0940b499fd5e6958",
      "parents": [
        "d964f294229150b425a054b5efada0602acb1cbf"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Wed Apr 08 00:01:01 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Apr 08 15:01:01 2026 +0800"
      },
      "message": "Revert \"build(deps): replace cmake version exclusion with uv exclude-newer\" (#525)\n\nReverts apache/tvm-ffi#524\n\nMade a mistake that I incorrectly pushed a staging branch to the\nprevious branch"
    },
    {
      "commit": "d964f294229150b425a054b5efada0602acb1cbf",
      "tree": "eeb8a512f7cab683eeccf37835976f68663c0ee2",
      "parents": [
        "bd87b3b04c0b9f7ff9fc73842507990ded91fae6"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Tue Apr 07 22:29:36 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Apr 07 22:29:36 2026 -0700"
      },
      "message": "build(deps): replace cmake version exclusion with uv exclude-newer (#524)\n\n## Summary\n\n- Remove the `cmake!\u003d4.3.1` version pin from dev dependencies, which was\na temporary workaround for a specific broken cmake release.\n- Add `[tool.uv] exclude-newer \u003d \"30 days\"` to prevent installing any\npackage released within the last 30 days, providing a more general and\nmaintainable guard against freshly-released broken packages across the\nentire dependency tree."
    },
    {
      "commit": "bd87b3b04c0b9f7ff9fc73842507990ded91fae6",
      "tree": "ce838318369bbc7409a8cb0a0940b499fd5e6958",
      "parents": [
        "8d1ba380c613b30b5910340ec009837729131db1"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Tue Apr 07 12:50:41 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Apr 07 12:50:41 2026 -0700"
      },
      "message": "chore(release): Version bump after release v0.1.10 (#522)"
    },
    {
      "commit": "8d1ba380c613b30b5910340ec009837729131db1",
      "tree": "65b23a91b22cad7eb6e69f311c4db64ef01bc672",
      "parents": [
        "3539d7077620dbade194bd231091cd4029924b83"
      ],
      "author": {
        "name": "Kathryn (Jinqi) Chen",
        "email": "65606304+Kathryn-cat@users.noreply.github.com",
        "time": "Thu Apr 02 11:28:42 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Apr 02 11:28:42 2026 -0700"
      },
      "message": "[fix] Move container stream scanning from Cython to C++ for efficiency (#521)\n\nWhen a packed FFI function receives containers (Array, List, Map, Dict)\ncontaining tensors, we scan for the first non-CPU tensor to capture\nstream context. Previously this scanning was done in Cython via repeated\npacked-function calls (size, getitem, iterator create/advance per\nelement). This PR registers a single C++ function\nffi.ContainerFindFirstNonCPUDevice that does the recursive scan\nnatively."
    },
    {
      "commit": "3539d7077620dbade194bd231091cd4029924b83",
      "tree": "a59c3a16c6dc7f569800535864c8a386793d5cfa",
      "parents": [
        "1fed0ae0421e614d45662e8ee6bcae353d3ab2ea"
      ],
      "author": {
        "name": "Kathryn (Jinqi) Chen",
        "email": "65606304+Kathryn-cat@users.noreply.github.com",
        "time": "Thu Apr 02 00:18:14 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Apr 02 00:18:14 2026 -0700"
      },
      "message": "[FEAT] Recursive DLPack container conversion for auto torch.Tensor return (#517)\n\n### Problem\n\nWhen a packed FFI function receives `torch.Tensor` inputs, the return\nvalue is automatically converted back to `torch.Tensor` via DLPack — but\nonly for bare ffi.Tensor returns. When the return is a container (Array,\nList, Map, Dict) containing tensors, the tensors inside remain as\nffi.Tensor, requiring manual per-element conversion.\n\n### Solution\n\nWe perform a lazy conversion of each element in the container from\nffi::Tensor to torch::Tensor when they\u0027re retrieved. A lazy conversion\nensures both semantic correctness of containers and reduce runtime\noverhead compared with eager conversion.\n\n### Stream Propagation\n| Container | Element | Stream set? | How |\n| :--- | :--- | :--- | :--- |\n| list/tuple | torch.Tensor | Yes | ConstructorCall → each element hits\nDLPackExchangeAPI_ setter |\n| list/tuple | ffi.Tensor | No | ConstructorCall → each element hits\nTensor_ setter (no stream) |\n| dict | torch.Tensor (values) | Yes | Same as above via ConstructorCall\n|\n| dict | ffi.Tensor (values) | No | Same as above |\n| ffi.Array/ffi.List (tagged) | ffi.Tensor | Yes | ContainerObject_\nsetter → _scan_seq_for_stream |\n| ffi.Map/ffi.Dict (tagged) | ffi.Tensor | Yes | ContainerObject_ setter\n→ _scan_map_for_stream |\n| ffi.Array/ffi.List (untagged) | ffi.Tensor | No | Object_ setter\n(pass-through) |\n| ffi.Map/ffi.Dict (untagged) | ffi.Tensor | No | Object_ setter\n(pass-through) |"
    },
    {
      "commit": "1fed0ae0421e614d45662e8ee6bcae353d3ab2ea",
      "tree": "f772f6b97252a8855f6137d48252630f84a95f60",
      "parents": [
        "61f90ebed458da702b4e89e260bf9f9568955fab"
      ],
      "author": {
        "name": "Akaash Parthasarathy",
        "email": "43900735+akaashrp@users.noreply.github.com",
        "time": "Wed Apr 01 15:29:51 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Apr 01 12:29:51 2026 -0700"
      },
      "message": "[FFI][Reflection] Lazily resolve KWARGS sentinel in auto-init (#519)\n\nThis PR intends to avoid the eager lookup of `ffi.GetKwargsObject`\nduring `MakeInit` construction. Instead, it resolves and caches the\nKWARGS sentinel via a function-local static (`GetKwargsSentinel`) when\n`__ffi_init__` is invoked. This removes static-init order dependence\nbetween reflection auto-init registration and global function\nregistration, preventing `Function ffi.GetKwargsObject not found`\nfailures."
    },
    {
      "commit": "61f90ebed458da702b4e89e260bf9f9568955fab",
      "tree": "e62311cd0d32af03ae84c1dccf53c7f908d1c231",
      "parents": [
        "1da563747d5552a4d8f6a9f2bac063426d9c1ba5"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Tue Mar 31 10:54:02 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Mar 31 13:54:02 2026 -0400"
      },
      "message": "fix(ci): pin pypa/gh-action-pypi-publish to SHA for Apache allowlist (#518)\n\n## Summary\n\n- Pin `pypa/gh-action-pypi-publish` from `@release/v1` (branch ref) to\n`@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e` (v1.13.0 SHA) in all three\npublish workflows\n- Fixes `startup_failure` in the \"Publish wheel\" workflow ([failed\nrun](https://github.com/apache/tvm-ffi/actions/runs/23773754182)) caused\nby Apache\u0027s org-level action allowlist requiring SHA-pinned third-party\nactions\n- Same class of fix as d8bd189 (#507), which pinned `astral-sh/setup-uv`\nand `pypa/cibuildwheel`\n\n### Files changed\n\n- `.github/workflows/publish_wheel.yml`\n- `.github/workflows/publish_orcjit_wheel.yml`\n- `.github/workflows/torch_c_dlpack.yml`\n\n## Test plan\n\n- [ ] Verify the \"Publish wheel\" workflow no longer fails with\n`startup_failure`\n- [ ] Confirm all three publish workflows pass CI"
    },
    {
      "commit": "1da563747d5552a4d8f6a9f2bac063426d9c1ba5",
      "tree": "60a41783188b6c0b7f693788a4be6bbcd08620d6",
      "parents": [
        "dbf64e88c5f171da493ea887acc7ae5887101676"
      ],
      "author": {
        "name": "Yaoyao Ding",
        "email": "dingyaoyao.cs@gmail.com",
        "time": "Fri Mar 27 10:19:23 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Mar 27 22:19:23 2026 +0800"
      },
      "message": "[OrcJIT] Add LLVM ORC JIT v2 dynamic object loader addon (#254)\n\nThis PR introduces a new addon package `tvm-ffi-orcjit` that enables\ndynamic loading of TVM-FFI exported object files (.o) at runtime using\nLLVM\u0027s ORC JIT v2 engine.\n\nThe addon provides a Python API for loading compiled object files, load\nthe tvm-ffi functions defined in the object files.\n\nThe API is organized around three main concepts:\n- **ExecutionSession**: A JIT compilation context that manages the\nlifetime of dynamic libraries.\n- **DynamicLibrary**: Represents a shared library that links multiple\nobject files.\n- **Object Files**: Compiled `.o` files containing TVM-FFI exported\nfunctions.\n\n## Usage Example\n\n```python\nfrom tvm_ffi_orcjit import create_session\n\n# Create an execution session (JIT compilation context)\nsession \u003d create_session()\n\n# Load an object file into the session, returns a DynamicLibrary handle\ndylib \u003d session.load(\"example.o\")\n\n# Get and call a function from the loaded object file\nadd_func \u003d dylib.get_function(\"simple_add\")\nresult \u003d add_func(1, 2)\nprint(f\"Result: {result}\")  # Output: Result: 3\n```\n\nFor incremental loading, you can add multiple object files to the same\nsession:\n\n```python\nsession \u003d create_session()\n\n# Load first object file\ndylib \u003d session.load(\"math_ops.o\")\nadd \u003d dylib.get_function(\"simple_add\")\n\n# Incrementally load more object files into the same library\ndylib.load(\"string_ops.o\")\n\n# Now both functions are accessible from the same library\nconcat \u003d dylib.get_function(\"string_concat\")\n```\n\nSee the test for more example.\n\n## TODO\n\n- Support Windows platform (currently Linux and macOS only)\n- Customize memory allocation for dynamic libraries (allow user-provided\nallocators)\n\n---------\n\nCo-authored-by: Yaxing Cai \u003ccaiyaxing666@gmail.com\u003e"
    },
    {
      "commit": "dbf64e88c5f171da493ea887acc7ae5887101676",
      "tree": "2216607a5e60f5de04c63b07edbdf8a4e8d301a9",
      "parents": [
        "63224e3f1e464cc62307223787926a48fc8df8c0"
      ],
      "author": {
        "name": "Tianqi Chen",
        "email": "tqchen@users.noreply.github.com",
        "time": "Thu Mar 26 20:47:21 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Mar 26 20:47:21 2026 -0400"
      },
      "message": "[FEAT] Add map_dataclass_to_tuple to make_kwargs_wrapper (#515)\n\nAdd a `map_dataclass_to_tuple` parameter to `make_kwargs_wrapper` and\n`make_kwargs_wrapper_from_signature` that accepts a list of argument\nnames whose dataclass values should be converted to tuples (via\n`dataclasses.astuple`) before being passed to the target function.\n\nThis enables callers to pass dataclass instances to FFI functions that\nexpect flattened tuple arguments, matching the calling convention. The\nconversion is injected into the generated wrapper code, so there is no\noverhead when the feature is not used."
    },
    {
      "commit": "63224e3f1e464cc62307223787926a48fc8df8c0",
      "tree": "0a92bf8e3be43fa587c9243a46436e6e102519ae",
      "parents": [
        "41d38fa32f361fd219463455e5ef061e43a85945"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Tue Mar 24 12:31:44 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Mar 24 12:31:44 2026 -0700"
      },
      "message": "fix(build): resolve type ambiguity and macro redefinition in unity builds (#512)\n\n## Summary\n- **`src/ffi/object.cc`**: Replace `using namespace tvm::ffi;` with a\nnamespace alias (`namespace ffi \u003d ::tvm::ffi;`) and fully qualify all\ntype names in the static init block. This prevents ambiguous type\nreferences (e.g. `Object` matching both `tvm::ffi::Object` and\n`tvm::runtime::Object`) in downstream wasm projects that include tvm-ffi\nsources in a unity build.\n- **`src/ffi/testing/testing.cc`**: Remove the `#define\nTVM_FFI_DLL_EXPORT_INCLUDE_METADATA 1` from the source file to avoid\nmacro redefinition warnings in unity builds where the macro is already\nset by the build system.\n- **`CMakeLists.txt`**: Add `target_compile_definitions(tvm_ffi_testing\nPRIVATE TVM_FFI_DLL_EXPORT_INCLUDE_METADATA\u003d1)` so the define is\nprovided via the build system instead of hardcoded in source.\n\n## Test plan\n- [ ] Verify existing C++ tests pass (`ctest` in CI)\n- [ ] Verify downstream wasm unity builds compile without ambiguity\nerrors or macro redefinition warnings"
    },
    {
      "commit": "41d38fa32f361fd219463455e5ef061e43a85945",
      "tree": "d8031fd76b13228a3838c199b589fb04e65acccc",
      "parents": [
        "d153a2c9407ee04ec3dc1ccbdf6a0664854337b7"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Mon Mar 23 07:38:54 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Mar 23 07:38:54 2026 -0700"
      },
      "message": "refactor(python)!: rename `structure\u003d` to `structural_eq\u003d` (#509)\n\n## Summary\n\n- Rename the `structure\u003d` parameter to `structural_eq\u003d` in `@py_class()`\nand `field()` to better convey that the parameter controls structural\nequality/hashing behavior\n- Update Cython layer (`type_info.pxi`) to read the new attribute name\n- Update all tests and documentation to use the new parameter name\n\n## Breaking Change\n\nThe `structure\u003d` parameter on `@py_class()` and `field()` has been\nrenamed to `structural_eq\u003d`.\n\n**Migration**: replace all occurrences of `structure\u003d` with\n`structural_eq\u003d` in your `@py_class()` and `field()` calls:\n\n```python\n# Before\n@py_class(structure\u003d\"tree\")\nclass MyNode(Object):\n    span: Object \u003d field(structure\u003d\"ignore\")\n\n# After\n@py_class(structural_eq\u003d\"tree\")\nclass MyNode(Object):\n    span: Object \u003d field(structural_eq\u003d\"ignore\")\n```\n\n## Test plan\n\n- [x] `uv pip install --force-reinstall --verbose -e .` (full C++\nrebuild required)\n- [x] `uv run pytest -vvs tests/python/test_structural_py_class.py`\n- [ ] Verify all pre-commit hooks pass (confirmed locally: all passed)\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)"
    },
    {
      "commit": "d153a2c9407ee04ec3dc1ccbdf6a0664854337b7",
      "tree": "d409562b5907742b6ba8061e41ede9923552c233",
      "parents": [
        "d8bd1890ba407181f18284a6714d1c8cca57dd52"
      ],
      "author": {
        "name": "Junru Shao",
        "email": "junrushao@apache.org",
        "time": "Sun Mar 22 14:24:35 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Mar 22 14:24:35 2026 -0700"
      },
      "message": "feat(python): auto-register __ffi_* dunder methods in @py_class as TypeMethod (#508)\n\n## Summary\n\n- Extend `@py_class` to detect and register recognized FFI dunder\nmethods (`__ffi_repr__`, `__ffi_eq__`, `__s_equal__`, etc.) defined on\nPython dataclasses, making them callable from C++ and other FFI\nlanguages\n- `_FFI_RECOGNIZED_METHODS` allowlist in `py_class.py` gates which\ndunders are collected; `_collect_py_methods()` scans class dict and\n`TypeInfo._register_py_methods()` registers via the C API\n(`TVMFFITypeRegisterMethod` + `TVMFFITypeRegisterAttr`)\n- No C++ changes — `dataclass.cc` is unmodified from upstream\n\n## Changes since v1\n\n- Rebased onto upstream/main (`d8bd1890`) which adds structural\nequality/hashing support (#507)\n- Resolved merge conflicts: preserved `structure_kind` /\n`STRUCTURE_KIND_MAP` from upstream\n- Applied Gemini Code Assist review feedback:\n- **HIGH**: Fixed `func_any` memory leak in `_register_py_methods` by\nadding `TVMFFIObjectDecRef` in a `try/finally` block\n- **MEDIUM**: Changed `_collect_py_methods` to iterate\n`cls.__dict__.items()` instead of `list(cls.__dict__)` + second lookup\n\n## Test plan\n\n- [x] 12 new dedicated tests covering allowlist filtering, registration,\nround-trip dispatch (repr, eq, compare, hash)\n- [x] All 693 tests pass (including structural equality tests that now\nwork with the `structure_kind` base from #507)\n- [ ] CI: lint, C++ tests, Python tests, Rust tests\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)"
    }
  ],
  "next": "d8bd1890ba407181f18284a6714d1c8cca57dd52"
}
