TVM-FFI OrcJIT
A Python package that enables dynamic loading of compiled object files (.o)
using LLVM ORC JIT v2, providing a flexible JIT execution environment for
TVM-FFI exported functions.
Features
- JIT Execution: Load and execute compiled object files at runtime using LLVM's ORC JIT v2
- High-Level Loading:
default_session().load_module(...)mirrorstvm_ffi.load_module, returning a plaintvm_ffi.Module - Unified Input: Load from a file path, in-memory object bytes, or a list mixing both
- Shared Session: A process-wide session so callers share process-symbol resolution and the Linux slab pool while loaded modules remain isolated
- Symbol Isolation: Separate
load_modulecalls define independent symbol namespaces, so they can define the same symbol without conflicts - Bounded-Range Memory: A growable Linux slab pool keeps JIT code/data close enough for 32-bit PC-relative relocations and supports explicit drained-slab reclamation
- Init/Fini Support: Handles static constructors/destructors across ELF (
.init_array/.ctors), Mach-O (__mod_init_func), and COFF (.CRT$XC*/.CRT$XT*) - Cross-Platform: Linux (x86_64, aarch64), macOS (arm64), Windows (AMD64)
- Multi-Compiler: Tested with LLVM Clang, GCC, Apple Clang, MSVC, and clang-cl
- TVM-FFI Integration: Seamlessly works with TVM-FFI's stable C ABI
- Python API: Simple Pythonic interface for JIT compilation and execution
Supported Platforms and Compilers
Object files compiled with any of the following compiler/platform combinations can be loaded and executed by the ORC JIT:
| Platform | Compilers | C | C++ |
|---|---|---|---|
| Linux (x86_64, aarch64) | LLVM Clang, GCC | yes | yes |
| macOS (arm64) | LLVM Clang, Apple Clang | yes | yes |
| Windows (AMD64) | LLVM Clang, MSVC, clang-cl | yes | no |
Windows is C-only across all compilers. C++ objects compiled with
TVM_FFI_DLL_EXPORT_TYPED_FUNC use try/catch (via TVM_FFI_SAFE_CALL_BEGIN/END),
which requires Itanium exception ABI symbols (__cxa_begin_catch,
__gxx_personality_v0, etc.) that the MSVC-built host process cannot provide.
Pure C objects using the TVMFFISafeCallType ABI work on all platforms.
Installation
Install from PyPI
pip install apache-tvm-ffi apache-tvm_ffi_orcjit
Build from Source
Prerequisites
- Python 3.10+, CMake 3.20+, C++17 compiler
- LLVM 23.1.1+ development libraries (
llvmdev,llvm-config) - Static
zlibandzstdlibraries (in the same prefix as LLVM)
Install LLVM via conda-forge
The easiest way to get all dependencies is via conda-forge:
conda create -p /opt/llvm -c conda-forge \
llvmdev=23.1.1 clangdev=23.1.1 compiler-rt=23.1.1 zlib zstd-static -y
export LLVM_PREFIX=/opt/llvm
On Windows:
conda create -p C:\opt\llvm -c conda-forge llvmdev=23.1.1 zlib zstd-static -y
set LLVM_PREFIX=C:\opt\llvm
Build and install
git clone --recursive https://github.com/apache/tvm-ffi.git
cd tvm-ffi
# Install tvm-ffi first
pip install -e .
# Build and install the orcjit addon
cd addons/tvm_ffi_orcjit
pip install -e .
The LLVM_PREFIX environment variable tells CMake where to find LLVM. If
LLVM is installed in a conda env or a standard system path, CMake can
auto-discover it and LLVM_PREFIX is not needed.
On Linux, each load_module call follows the same default compiler selection
as tvm_ffi.cpp.build: $CXX, or c++ when unset. ORC asks that compiler for
its libstdc++.so.6 and optional libstdc++_nonshared.a, then keeps both local
to the new JITDylib. Discovery is cached, and load_module(..., cxx="g++-14")
can select a different toolchain without supplying runtime-library paths.
Usage
Basic Example
The high-level API mirrors tvm_ffi.load_module: a process-wide shared session
plus a load_module that accepts a path, in-memory object bytes, or a list of
either, and returns a plain tvm_ffi.Module.
import tvm_ffi_orcjit as oj
# Shared process-wide session (created once, cached).
session = oj.default_session()
# Load a single object file by path.
mod = session.load_module("example.o")
# Call an exported function.
result = mod.add(1, 2)
print(f"Result: {result}") # Output: Result: 3
Loading Multiple Objects and In-Memory Bytes
Objects passed together are linked into one module (the same way a multi-object shared library links). Each element may be a path or an object-file image in memory.
from pathlib import Path
session = oj.default_session()
mod = session.load_module(
[
"math_ops.o", # path
Path("kernel.o").read_bytes(), # in-memory object bytes
]
)
result = mod.call_math(10, 20)
Isolated Sessions
default_session() is shared across the process. For an isolated symbol
namespace or a tuned memory arena, construct an ExecutionSession directly:
from tvm_ffi_orcjit import ExecutionSession
session = ExecutionSession() # independent LLVM ExecutionSession
mod = session.load_module("impl.o")
Writing Functions for OrcJIT
C++ (Linux/macOS)
#include <tvm/ffi/function.h>
TVM_FFI_DLL_EXPORT_TYPED_FUNC(add, [](int a, int b) {
return a + b;
});
Compile: clang++ -std=c++17 -fPIC -O2 -c -o example.o example.cc
Pure C (all platforms including Windows)
#include <tvm/ffi/c_api.h>
TVM_FFI_DLL_EXPORT int __tvm_ffi_add(
void* self, const TVMFFIAny* args, int32_t num_args, TVMFFIAny* result) {
result->type_index = kTVMFFIInt;
result->v_int64 = args[0].v_int64 + args[1].v_int64;
return 0;
}
Compile: clang -O2 -c -o example.o example.c
How It Works
- LLJIT: Built on LLVM's ORC JIT v2 with
ObjectLinkingLayer(JITLink) for all platforms. - ELF Lifecycle (Linux): LLVM 23.1.1+
ELFNixPlatformruns ordered constructors and destructors throughLLJIT::initialize/deinitialize. - InitFiniPlugin (macOS/Windows): A local
ObjectLinkingLayer::Pluginhandles Mach-O__mod_init_func/__mod_term_funcand COFF.CRT$XC*/.CRT$XT*while those ORC platforms remain unsuitable. - DLL Import Stubs (Windows): Custom
DefinitionGeneratorthat resolves host process symbols from all loaded DLLs and creates__imp_*pointer stubs in JIT memory, keeping all fixups within PCRel32 range. - SEH Stripping (Windows):
ObjectTransformLayerstrips.pdata/.xdatarelocations from COFF objects before JITLink graph building, working around a JITLink limitation with COMDAT section symbols.
Refer to ORCJIT_PRIMER.md for background on object files, linking, LLVM ORC JIT v2, and the addon's architecture.
Project Structure
tvm_ffi_orcjit/
├── CMakeLists.txt # Build configuration
├── pyproject.toml # Python package metadata
├── src/ffi/
│ ├── orcjit_session.cc # ExecutionSession (LLJIT setup, plugins)
│ ├── orcjit_session.h
│ ├── orcjit_dylib.cc # JIT dylib module (object loading, symbol lookup)
│ ├── orcjit_dylib.h
│ ├── orcjit_memory_manager.* # Growable Linux slab pool
│ ├── orcjit_slab.* # Contiguous-VA allocator and page protection
│ ├── llvm_patches/ # Isolated upstream LLVM workarounds
│ └── orcjit_utils.h # LLVM error handling utilities
├── python/tvm_ffi_orcjit/
│ ├── __init__.py # Module exports and library loading
│ └── session.py # Python ExecutionSession + default_session
├── tests/ # See tests/README.md
└── examples/quick-start/ # Complete example with CMake
CI
Runs on Linux (x86_64, aarch64), macOS (arm64), Windows (AMD64) via
cibuildwheel. Each platform builds test objects with multiple compilers
and runs the full test suite. See the orcjit job in .github/workflows/ci_test.yml.
Troubleshooting
"Cannot find global function" error
The shared library wasn't loaded. Reinstall: pip install --force-reinstall apache-tvm_ffi_orcjit
"Duplicate definition of symbol" error
Use separate libraries for different implementations of the same symbol.
"Symbol not found" error
Ensure functions are exported with TVM-FFI macros (TVM_FFI_DLL_EXPORT_TYPED_FUNC
for C++, or __tvm_ffi_ prefix for C).
Relocation errors on Windows
MSVC/clang-cl objects must be compiled with /GS- to disable buffer security
checks (__security_cookie) which are CRT symbols the JIT cannot resolve.
LLVM version mismatch
The package requires LLVM 23.1.1+. Set LLVM_PREFIX to the LLVM install prefix:
export LLVM_PREFIX=/path/to/llvm
Reclaiming unused JIT memory on Linux
Dropping a module returns its regions to the session's slab pool for reuse. To
return fully drained slabs to the operating system, call
session.clear_free_slabs(). The call is synchronized with concurrent JIT work.
License
Apache License 2.0
Release files for apache-tvm-ffi-orcjit 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| apache_tvm_ffi_orcjit-0.1.2-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| apache_tvm_ffi_orcjit-0.1.2-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | Python 3 | none | Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 | Details |
| apache_tvm_ffi_orcjit-0.1.2-py3-none-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl | Python 3 | none | Linux glibc 2.27+ ARM64, Linux glibc 2.28+ ARM64 | Details |
| apache_tvm_ffi_orcjit-0.1.2-py3-none-macosx_11_0_arm64.whl | Python 3 | none | macOS 11.0+ ARM64 | Details |
Total release size: 68.8 MB
Release files / apache_tvm_ffi_orcjit-0.1.2-py3-none-win_amd64.whl
| Download URL | apache_tvm_ffi_orcjit-0.1.2-py3-none-win_amd64.whl |
|---|---|
| Size | 12.6 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
9ff30af2e30b8cb35a94a7ecff6b566cc1ec320e07312cfd692eec08b6ccee23
|
|
BLAKE2b-256 checksum How to use checksums |
e3921ad399ac5bd3694801f32505077a3aff36a7518c4180711e55292ed8844d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / apache_tvm_ffi_orcjit-0.1.2-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | apache_tvm_ffi_orcjit-0.1.2-py3-none-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 21.1 MB |
| Tags | Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
cd0a2e477df75d591090dbcb027ec5891a18221be0aeee08d1a41b9ba3a5a78d
|
|
BLAKE2b-256 checksum How to use checksums |
89fdd8dce24b19c44c3c9babd28db720a6297e8913b03969eed570001db3a659
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / apache_tvm_ffi_orcjit-0.1.2-py3-none-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl
| Download URL | apache_tvm_ffi_orcjit-0.1.2-py3-none-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl |
|---|---|
| Size | 20.3 MB |
| Tags | Linux glibc 2.27+ ARM64 Linux glibc 2.28+ ARM64 Python 3 |
|
SHA-256 checksum How to use checksums |
292d7ac5df46a90ff4b9966a432b68a24a8642dbe5fac1e7c1e7abe172d50535
|
|
BLAKE2b-256 checksum How to use checksums |
8d501014ee2414a17861bc3ac203316b573ae34625986b7e1c43c8508eadf689
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / apache_tvm_ffi_orcjit-0.1.2-py3-none-macosx_11_0_arm64.whl
| Download URL | apache_tvm_ffi_orcjit-0.1.2-py3-none-macosx_11_0_arm64.whl |
|---|---|
| Size | 14.9 MB |
| Tags | Python 3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
a8ed6cfe8792891ebb2144b8d4174f38073b302f9372be4ee73731673a7fb128
|
|
BLAKE2b-256 checksum How to use checksums |
8f4e6db6afa6b4f8aeb5fa520edb82b2345f2671dc16c5eac9190f488848133e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency log