yaoyaoding commented on code in PR #254:
URL: https://github.com/apache/tvm-ffi/pull/254#discussion_r2977123252


##########
addons/tvm-ffi-orcjit/examples/quick-start/run.py:
##########
@@ -0,0 +1,122 @@
+#!/usr/bin/env python3
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Quick Start Example - Load and call functions from compiled object files.
+
+This script demonstrates how to:
+1. Create an ExecutionSession instance
+2. Create a DynamicLibrary
+3. Load a compiled object file (C++ or pure C)
+4. Get functions by name
+5. Call them like regular Python functions
+
+Usage:
+    python run.py          # Load C++ object file (add.o)
+    python run.py --lang c # Load pure C object file (add_c.o)
+"""
+
+import argparse
+import sys
+from pathlib import Path
+
+# Use the installed package if available; fall back to source tree for 
editable dev
+try:
+    from tvm_ffi_orcjit import ExecutionSession
+except ImportError:
+    sys.path.insert(0, str(Path(__file__).parent.parent.parent / "python"))
+    from tvm_ffi_orcjit import ExecutionSession
+
+
+def main() -> int:
+    """Run the quick start example."""
+    parser = argparse.ArgumentParser(description="Quick Start Example")
+    parser.add_argument(
+        "--lang",
+        choices=["cpp", "c"],
+        default="cpp",
+        help="Language variant to load: 'cpp' for add.o (default), 'c' for 
add_c.o",
+    )
+    args = parser.parse_args()
+
+    # Select object file based on language choice
+    if args.lang == "c":
+        obj_file = Path("add_c.o")
+    else:
+        obj_file = Path("add.o")
+
+    if not obj_file.exists():
+        print(f"Error: {obj_file} not found!")
+        print("Please build with CMake first:")
+        print("  cmake -B build && cmake --build build")
+        return 1
+
+    print(f"Loading object file: {obj_file} (lang={args.lang})")
+
+    # Create execution session and dynamic library
+    session = ExecutionSession()
+    lib = session.create_library()
+    lib.add(str(obj_file))
+
+    print("Object file loaded successfully\n")
+
+    # Get and call the 'add' function
+    print("=== Testing add function ===")
+    add = lib.get_function("add")
+    result = add(10, 20)
+    print(f"add(10, 20) = {result}")
+    assert result == 30, f"Expected 30, got {result}"
+
+    # Get and call the 'multiply' function
+    print("\n=== Testing multiply function ===")
+    multiply = lib.get_function("multiply")
+    result = multiply(7, 6)
+    print(f"multiply(7, 6) = {result}")
+    assert result == 42, f"Expected 42, got {result}"
+
+    # Get and call the 'fibonacci' function
+    print("\n=== Testing fibonacci function ===")
+    fibonacci = lib.get_function("fibonacci")
+    result = fibonacci(10)
+    print(f"fibonacci(10) = {result}")
+    assert result == 55, f"Expected 55, got {result}"
+
+    if args.lang == "cpp":
+        # String concatenation only available in C++ variant (uses std::string)
+        print("\n=== Testing concat function ===")
+        concat = lib.get_function("concat")
+        result = concat("Hello, ", "World!")
+        print(f"concat('Hello, ', 'World!') = '{result}'")
+        assert result == "Hello, World!", f"Expected 'Hello, World!', got 
'{result}'"
+        # Release the returned String object before JIT module is destroyed
+        del result
+        del concat

Review Comment:
   it's not very pythonic. Can we add a reference to concat Function in result 
String to avoid explicit del order requiement?



##########
addons/tvm-ffi-orcjit/python/tvm_ffi_orcjit/session.py:
##########
@@ -0,0 +1,90 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""ORC JIT Execution Session."""
+
+from __future__ import annotations
+
+import sys
+
+from tvm_ffi import Object, register_object
+
+from . import _ffi_api, _lib_dir
+from .dylib import DynamicLibrary
+
+
+def _find_orc_rt_library() -> str | None:
+    """Find the bundled liborc_rt library in the same directory as the 
.so/.dll."""
+    # Windows: skip ORC runtime entirely. LLVM's COFFPlatform (loaded via
+    # ExecutorNativePlatform with liborc_rt) depends on MSVC C++ runtime 
symbols
+    # that are not available in the JIT environment. On Windows, ORC JIT uses a
+    # C-only strategy: JIT objects are compiled as pure C (TVMFFISafeCallType 
ABI),
+    # avoiding all C++ runtime dependencies (magic statics, RTTI, sized delete,
+    # SEH, COMDAT). Our custom InitFiniPlugin handles .CRT$XC*/.CRT$XT* 
init/fini
+    # sections, and DLLImportDefinitionGenerator resolves __imp_ DLL import 
stubs.
+    if sys.platform == "win32":
+        return None
+    patterns = ["liborc_rt*.a"]

Review Comment:
   I did not find public documentation around this archive: `liborc_rt*.a`, is 
there any docs you find? Interested to learn more.



##########
addons/tvm-ffi-orcjit/src/ffi/orcjit_session.cc:
##########
@@ -0,0 +1,664 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file orcjit_session.cc
+ * \brief LLVM ORC JIT ExecutionSession implementation
+ */
+
+#include "orcjit_session.h"
+
+#include <llvm/ExecutionEngine/JITLink/JITLink.h>
+#include <llvm/ExecutionEngine/JITLink/x86_64.h>
+#include <llvm/ExecutionEngine/Orc/AbsoluteSymbols.h>
+#include <llvm/ExecutionEngine/Orc/LLJIT.h>
+#include <llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h>
+#include <llvm/ExecutionEngine/Orc/ObjectTransformLayer.h>
+#include <llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h>
+#include <llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h>
+#include <llvm/Support/DynamicLibrary.h>
+#include <llvm/Support/Error.h>
+#include <llvm/Support/TargetSelect.h>
+#include <llvm/TargetParser/SubtargetFeature.h>
+#include <tvm/ffi/cast.h>
+#include <tvm/ffi/error.h>
+#include <tvm/ffi/object.h>
+#include <tvm/ffi/reflection/registry.h>
+
+#include <cstddef>
+#include <cstring>
+
+#ifdef _WIN32
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <psapi.h>
+#include <windows.h>
+#endif
+
+#include "orcjit_dylib.h"
+#include "orcjit_utils.h"
+
+namespace tvm {
+namespace ffi {
+namespace orcjit {
+
+// Initialize LLVM native target (only once)
+struct LLVMInitializer {
+  LLVMInitializer() {
+    llvm::InitializeNativeTarget();
+    llvm::InitializeNativeTargetAsmPrinter();
+    llvm::InitializeNativeTargetAsmParser();
+  }
+};
+
+static LLVMInitializer llvm_initializer;
+
+class InitFiniPlugin : public llvm::orc::ObjectLinkingLayer::Plugin {
+  ORCJITExecutionSession session_;
+
+ public:
+  explicit InitFiniPlugin(ORCJITExecutionSession session) : 
session_(std::move(session)) {}

Review Comment:
   `InitFiniPlugin` holds a strong `ORCJITExecutionSession` ref, but the plugin 
is owned by ObjectLinkingLayer`, which is owned by `jit_`, which is owned by 
`ORCJITExecutionSessionObj`. This cycle: session → jit_ → layer → plugin → 
session — will prevent the session from ever being destroyed. The plugin should 
hold a raw/weak pointer instead.
   
   (found by claude)



##########
addons/tvm-ffi-orcjit/python/tvm_ffi_orcjit/session.py:
##########
@@ -0,0 +1,90 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""ORC JIT Execution Session."""
+
+from __future__ import annotations
+
+import sys
+
+from tvm_ffi import Object, register_object
+
+from . import _ffi_api, _lib_dir
+from .dylib import DynamicLibrary
+
+
+def _find_orc_rt_library() -> str | None:
+    """Find the bundled liborc_rt library in the same directory as the 
.so/.dll."""
+    # Windows: skip ORC runtime entirely. LLVM's COFFPlatform (loaded via
+    # ExecutorNativePlatform with liborc_rt) depends on MSVC C++ runtime 
symbols
+    # that are not available in the JIT environment. On Windows, ORC JIT uses a

Review Comment:
   Can I know why MSVC C++ runtime is not available in the JIT environment? 



##########
addons/tvm-ffi-orcjit/src/ffi/orcjit_dylib.cc:
##########
@@ -0,0 +1,207 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file orcjit_dylib.cc
+ * \brief LLVM ORC JIT DynamicLibrary implementation
+ */
+
+#include "orcjit_dylib.h"
+
+#include <llvm/ExecutionEngine/Orc/Core.h>
+#include <llvm/ExecutionEngine/Orc/LLJIT.h>
+#include <llvm/Object/ObjectFile.h>
+#include <llvm/Support/Error.h>
+#include <llvm/Support/MemoryBuffer.h>
+#include <tvm/ffi/c_api.h>
+#include <tvm/ffi/cast.h>
+#include <tvm/ffi/container/array.h>
+#include <tvm/ffi/error.h>
+#include <tvm/ffi/extra/c_env_api.h>
+#include <tvm/ffi/extra/module.h>
+#include <tvm/ffi/function.h>
+#include <tvm/ffi/reflection/registry.h>
+
+#include "orcjit_session.h"
+#include "orcjit_utils.h"
+
+namespace tvm {
+namespace ffi {
+namespace orcjit {
+
+ORCJITDynamicLibraryObj::ORCJITDynamicLibraryObj(ORCJITExecutionSession 
session,
+                                                 llvm::orc::JITDylib* dylib, 
llvm::orc::LLJIT* jit,
+                                                 String name)
+    : session_(std::move(session)), dylib_(dylib), jit_(jit), 
name_(std::move(name)) {
+  if (void** ctx_addr = 
reinterpret_cast<void**>(GetSymbol(ffi::symbol::tvm_ffi_library_ctx))) {
+    *ctx_addr = this;
+  }
+  Module::VisitContextSymbols([this](const ffi::String& name, void* symbol) {
+    if (void** ctx_addr = 
reinterpret_cast<void**>(GetSymbol(ffi::symbol::tvm_ffi_library_ctx))) {
+      *ctx_addr = symbol;
+    }
+  });
+  TVM_FFI_CHECK(dylib_ != nullptr, ValueError) << "JITDylib cannot be null";
+  TVM_FFI_CHECK(jit_ != nullptr, ValueError) << "LLJIT cannot be null";
+}
+
+ORCJITDynamicLibraryObj::~ORCJITDynamicLibraryObj() {
+#if defined(__linux__) || defined(_WIN32)
+  // Linux/Windows: run section-based deinitializers (.fini_array, .dtors, 
.CRT$XT*)
+  // collected by our custom InitFiniPlugin.
+  session_->RunPendingDeinitializers(GetJITDylib());
+#else
+  // macOS: native platform's deinitialize drains __cxa_atexit handlers
+  // (registered during initialization) via the ORC runtime.
+  if (auto err = jit_->deinitialize(*dylib_)) {
+    llvm::consumeError(std::move(err));
+  }
+#endif
+}
+
+void ORCJITDynamicLibraryObj::AddObjectFile(const String& path) {
+  // Read object file
+  auto buffer_or_err = llvm::MemoryBuffer::getFile(path.c_str());
+  if (!buffer_or_err) {
+    TVM_FFI_THROW(IOError) << "Failed to read object file: " << path;
+  }
+
+  // Add object file to this JITDylib
+  call_llvm(jit_->addObjectFile(*dylib_, std::move(*buffer_or_err)), "Failed 
to add object file");
+}
+
+void ORCJITDynamicLibraryObj::SetLinkOrder(const 
std::vector<llvm::orc::JITDylib*>& dylibs) {
+  // Rebuild the link order: user-specified libraries first, then the LLJIT
+  // default link order (Main → Platform → ProcessSymbols).  Preserving the
+  // default link order is essential — without ProcessSymbols, C++ objects
+  // that need host-process symbols (runtime, libtvm_ffi) would fail to link.
+  link_order_.clear();
+
+  for (auto* lib : dylibs) {
+    link_order_.emplace_back(lib, 
llvm::orc::JITDylibLookupFlags::MatchAllSymbols);
+  }
+  for (auto& kv : jit_->defaultLinkOrder()) {
+    link_order_.emplace_back(kv.first, kv.second);
+  }
+
+  // Set the link order in the LLVM JITDylib
+  dylib_->setLinkOrder(link_order_, false);
+}
+
+void* ORCJITDynamicLibraryObj::GetSymbol(const String& name) {
+  // Build search order: this dylib first, then all linked dylibs
+  llvm::orc::JITDylibSearchOrder search_order;
+  search_order.emplace_back(dylib_, 
llvm::orc::JITDylibLookupFlags::MatchAllSymbols);
+  // Append linked libraries
+  search_order.insert(search_order.end(), link_order_.begin(), 
link_order_.end());
+
+  // Look up symbol using the full search order
+  auto symbol_or_err =
+      jit_->getExecutionSession().lookup(search_order, 
jit_->mangleAndIntern(name.c_str()));
+
+#if defined(__linux__) || defined(_WIN32)
+  // Linux/Windows: run initializers collected by our custom InitFiniPlugin.
+  session_->RunPendingInitializers(GetJITDylib());
+#else
+  // macOS: use native platform's init mechanism (handles __mod_init_func
+  // and __cxa_atexit registration).
+  if (auto err = jit_->initialize(*dylib_)) {

Review Comment:
   is it safe to call this function multiple times? each GetSymbol call will 
call this function.



##########
addons/tvm-ffi-orcjit/python/tvm_ffi_orcjit/session.py:
##########
@@ -0,0 +1,90 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+"""ORC JIT Execution Session."""
+
+from __future__ import annotations
+
+import sys
+
+from tvm_ffi import Object, register_object
+
+from . import _ffi_api, _lib_dir
+from .dylib import DynamicLibrary
+
+
+def _find_orc_rt_library() -> str | None:
+    """Find the bundled liborc_rt library in the same directory as the 
.so/.dll."""
+    # Windows: skip ORC runtime entirely. LLVM's COFFPlatform (loaded via
+    # ExecutorNativePlatform with liborc_rt) depends on MSVC C++ runtime 
symbols
+    # that are not available in the JIT environment. On Windows, ORC JIT uses a
+    # C-only strategy: JIT objects are compiled as pure C (TVMFFISafeCallType 
ABI),
+    # avoiding all C++ runtime dependencies (magic statics, RTTI, sized delete,
+    # SEH, COMDAT). Our custom InitFiniPlugin handles .CRT$XC*/.CRT$XT* 
init/fini
+    # sections, and DLLImportDefinitionGenerator resolves __imp_ DLL import 
stubs.
+    if sys.platform == "win32":
+        return None
+    patterns = ["liborc_rt*.a"]
+    for pattern in patterns:
+        for lib_path in _lib_dir.glob(pattern):
+            return str(lib_path)
+    return None
+
+
+@register_object("orcjit.ExecutionSession")
+class ExecutionSession(Object):
+    """ORC JIT Execution Session.
+
+    Manages the LLVM ORC JIT execution environment and creates dynamic 
libraries (JITDylibs).
+    This is the top-level context for JIT compilation and symbol management.
+
+    Examples
+    --------
+    >>> session = ExecutionSession()
+    >>> lib = session.create_library(name="main")
+    >>> lib.add("add.o")
+    >>> add_func = lib.get_function("add")
+
+    """
+
+    def __init__(self, orc_rt_path: str | None = None) -> None:
+        """Initialize ExecutionSession.
+
+        Args:
+            orc_rt_path: Optional path to the liborc_rt library. If not 
provided,
+                        it will be automatically discovered using clang.
+
+        """
+        if orc_rt_path is None:
+            orc_rt_path = _find_orc_rt_library()
+            if orc_rt_path is None:
+                orc_rt_path = ""
+        self.__init_handle_by_constructor__(_ffi_api.ExecutionSession, 
orc_rt_path)  # type: ignore
+
+    def create_library(self, name: str = "") -> DynamicLibrary:
+        """Create a new dynamic library associated with this execution session.
+
+        Args:
+            name: Optional name for the library. If empty, a unique name will 
be generated.
+
+        Returns:
+            A new DynamicLibrary instance.
+
+        """
+        handle = _ffi_api.ExecutionSessionCreateDynamicLibrary(self, name)  # 
type: ignore
+        lib = DynamicLibrary.__new__(DynamicLibrary)
+        lib.__move_handle_from__(handle)

Review Comment:
   If the ExecutionSessionCreateDynamicLibrary directly returns a 
DynamicLibrary, can this be simplified to something like `return 
_ffi_api.ExecutionSessionCreateDynamicLibrary(self, name)`?



##########
addons/tvm-ffi-orcjit/examples/quick-start/run.py:
##########
@@ -0,0 +1,122 @@
+#!/usr/bin/env python3
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+"""Quick Start Example - Load and call functions from compiled object files.
+
+This script demonstrates how to:
+1. Create an ExecutionSession instance
+2. Create a DynamicLibrary
+3. Load a compiled object file (C++ or pure C)
+4. Get functions by name
+5. Call them like regular Python functions
+
+Usage:
+    python run.py          # Load C++ object file (add.o)
+    python run.py --lang c # Load pure C object file (add_c.o)
+"""
+
+import argparse
+import sys
+from pathlib import Path
+
+# Use the installed package if available; fall back to source tree for 
editable dev
+try:
+    from tvm_ffi_orcjit import ExecutionSession
+except ImportError:
+    sys.path.insert(0, str(Path(__file__).parent.parent.parent / "python"))
+    from tvm_ffi_orcjit import ExecutionSession
+
+
+def main() -> int:
+    """Run the quick start example."""
+    parser = argparse.ArgumentParser(description="Quick Start Example")
+    parser.add_argument(
+        "--lang",
+        choices=["cpp", "c"],
+        default="cpp",
+        help="Language variant to load: 'cpp' for add.o (default), 'c' for 
add_c.o",
+    )
+    args = parser.parse_args()
+
+    # Select object file based on language choice
+    if args.lang == "c":
+        obj_file = Path("add_c.o")
+    else:
+        obj_file = Path("add.o")
+
+    if not obj_file.exists():
+        print(f"Error: {obj_file} not found!")
+        print("Please build with CMake first:")
+        print("  cmake -B build && cmake --build build")
+        return 1
+
+    print(f"Loading object file: {obj_file} (lang={args.lang})")
+
+    # Create execution session and dynamic library
+    session = ExecutionSession()
+    lib = session.create_library()
+    lib.add(str(obj_file))
+
+    print("Object file loaded successfully\n")
+
+    # Get and call the 'add' function
+    print("=== Testing add function ===")
+    add = lib.get_function("add")
+    result = add(10, 20)
+    print(f"add(10, 20) = {result}")
+    assert result == 30, f"Expected 30, got {result}"
+
+    # Get and call the 'multiply' function
+    print("\n=== Testing multiply function ===")
+    multiply = lib.get_function("multiply")
+    result = multiply(7, 6)
+    print(f"multiply(7, 6) = {result}")
+    assert result == 42, f"Expected 42, got {result}"
+
+    # Get and call the 'fibonacci' function
+    print("\n=== Testing fibonacci function ===")
+    fibonacci = lib.get_function("fibonacci")
+    result = fibonacci(10)
+    print(f"fibonacci(10) = {result}")
+    assert result == 55, f"Expected 55, got {result}"
+
+    if args.lang == "cpp":
+        # String concatenation only available in C++ variant (uses std::string)
+        print("\n=== Testing concat function ===")
+        concat = lib.get_function("concat")
+        result = concat("Hello, ", "World!")
+        print(f"concat('Hello, ', 'World!') = '{result}'")
+        assert result == "Hello, World!", f"Expected 'Hello, World!', got 
'{result}'"
+        # Release the returned String object before JIT module is destroyed
+        del result
+        del concat
+
+    print("\n" + "=" * 50)
+    print("All tests passed successfully!")
+    print("=" * 50)
+
+    # Cleanup: release references in correct order (functions, lib, session)
+    del add, multiply, fibonacci
+    del lib
+    del session

Review Comment:
   Do we need the user to handle the resource destroy explicitly? 



##########
addons/tvm-ffi-orcjit/examples/quick-start/README.md:
##########
@@ -0,0 +1,92 @@
+<!--- Licensed to the Apache Software Foundation (ASF) under one -->
+<!--- or more contributor license agreements.  See the NOTICE file -->
+<!--- distributed with this work for additional information -->
+<!--- regarding copyright ownership.  The ASF licenses this file -->
+<!--- to you under the Apache License, Version 2.0 (the -->
+<!--- "License"); you may not use this file except in compliance -->
+<!--- with the License.  You may obtain a copy of the License at -->
+
+<!---   http://www.apache.org/licenses/LICENSE-2.0 -->
+
+<!--- Unless required by applicable law or agreed to in writing, -->
+<!--- software distributed under the License is distributed on an -->
+<!--- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -->
+<!--- KIND, either express or implied.  See the License for the -->
+<!--- specific language governing permissions and limitations -->
+<!--- under the License. -->
+
+# Quick Start Example
+
+Demonstrates basic usage of tvm-ffi-orcjit: compile functions to object files,
+load them into the ORC JIT at runtime, and call them from Python.
+
+## Files
+
+| File | Description |
+| ------ | ------------- |
+| `add.cc` | C++ source using `TVM_FFI_DLL_EXPORT_TYPED_FUNC` (automatic type 
marshaling, supports `std::string`) |
+| `add_c.c` | Pure C source using `TVMFFISafeCallType` ABI (`__tvm_ffi_` 
prefix). No C++ runtime needed. |
+| `run.py` | Python script that loads and calls the compiled functions |
+| `CMakeLists.txt` | Build configuration for both variants |
+
+## Prerequisites
+
+- Python 3.10+, CMake 3.18+, C/C++ compiler
+- `apache-tvm-ffi` and `tvm-ffi-orcjit` packages installed
+
+## Steps
+
+### 1. Build the object files
+
+```bash
+cmake -B build
+cmake --build build
+```
+
+This produces `add.o` (C++) and `add_c.o` (pure C). On Windows, only the C
+variant is built (C++ is not supported for ORC JIT on Windows).
+
+### 2. Run
+
+```bash
+# C++ variant (Linux/macOS)
+python run.py
+
+# Pure C variant (all platforms including Windows)
+python run.py --lang c
+```
+
+## How It Works
+
+**C++ variant** (`add.cc`): Functions are exported with
+`TVM_FFI_DLL_EXPORT_TYPED_FUNC`, which wraps a typed C++ lambda/function into
+TVM-FFI's packed calling convention. Supports C++ types like `std::string`.
+
+**C variant** (`add_c.c`): Functions follow the `TVMFFISafeCallType` ABI
+directly — each function is named `__tvm_ffi_<name>` and manually packs
+arguments/results via `TVMFFIAny`. Zero C++ dependencies, works on all
+platforms including Windows with MSVC or clang-cl.
+
+**Python side** (`run.py`):
+
+```python
+from tvm_ffi_orcjit import ExecutionSession
+
+session = ExecutionSession()       # Create ORC JIT session
+lib = session.create_library()     # Create a JITDylib
+lib.add("add_c.o")                 # Load object file into JIT
+add = lib.get_function("add")      # Look up symbol
+print(add(10, 20))                 # Call like a normal function → 30
+```
+
+## Platform Notes
+
+| Platform | C++ (`add.o`) | C (`add_c.o`) |
+| ---------- | :-: | :-: |
+| Linux (Clang/GCC) | yes | yes |
+| macOS (Clang/Apple Clang) | yes | yes |
+| Windows (all compilers) | no | yes |
+
+C++ is not supported for ORC JIT on Windows. The 
`TVM_FFI_DLL_EXPORT_TYPED_FUNC`
+macro uses `try`/`catch` which requires Itanium exception ABI symbols that the
+MSVC-built host process cannot provide. Use the pure C variant on Windows.

Review Comment:
   Is this a general problem for `TVM_FFI_DLL_EXPORT_TYPED_FUNC` on Windows, or 
it's a specific problem for orcjitv2 on windows? 



##########
addons/tvm-ffi-orcjit/src/ffi/orcjit_dylib.cc:
##########
@@ -0,0 +1,207 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file orcjit_dylib.cc
+ * \brief LLVM ORC JIT DynamicLibrary implementation
+ */
+
+#include "orcjit_dylib.h"
+
+#include <llvm/ExecutionEngine/Orc/Core.h>
+#include <llvm/ExecutionEngine/Orc/LLJIT.h>
+#include <llvm/Object/ObjectFile.h>
+#include <llvm/Support/Error.h>
+#include <llvm/Support/MemoryBuffer.h>
+#include <tvm/ffi/c_api.h>
+#include <tvm/ffi/cast.h>
+#include <tvm/ffi/container/array.h>
+#include <tvm/ffi/error.h>
+#include <tvm/ffi/extra/c_env_api.h>
+#include <tvm/ffi/extra/module.h>
+#include <tvm/ffi/function.h>
+#include <tvm/ffi/reflection/registry.h>
+
+#include "orcjit_session.h"
+#include "orcjit_utils.h"
+
+namespace tvm {
+namespace ffi {
+namespace orcjit {
+
+ORCJITDynamicLibraryObj::ORCJITDynamicLibraryObj(ORCJITExecutionSession 
session,
+                                                 llvm::orc::JITDylib* dylib, 
llvm::orc::LLJIT* jit,
+                                                 String name)
+    : session_(std::move(session)), dylib_(dylib), jit_(jit), 
name_(std::move(name)) {
+  if (void** ctx_addr = 
reinterpret_cast<void**>(GetSymbol(ffi::symbol::tvm_ffi_library_ctx))) {
+    *ctx_addr = this;
+  }
+  Module::VisitContextSymbols([this](const ffi::String& name, void* symbol) {
+    if (void** ctx_addr = 
reinterpret_cast<void**>(GetSymbol(ffi::symbol::tvm_ffi_library_ctx))) {
+      *ctx_addr = symbol;
+    }
+  });
+  TVM_FFI_CHECK(dylib_ != nullptr, ValueError) << "JITDylib cannot be null";
+  TVM_FFI_CHECK(jit_ != nullptr, ValueError) << "LLJIT cannot be null";
+}
+
+ORCJITDynamicLibraryObj::~ORCJITDynamicLibraryObj() {
+#if defined(__linux__) || defined(_WIN32)
+  // Linux/Windows: run section-based deinitializers (.fini_array, .dtors, 
.CRT$XT*)
+  // collected by our custom InitFiniPlugin.
+  session_->RunPendingDeinitializers(GetJITDylib());
+#else

Review Comment:
   the current support for __linux__ and _WIN32 platform are not enough? maybe 
add some documentation to explain the current status of orcjit on these 
platforms.



##########
addons/tvm-ffi-orcjit/src/ffi/orcjit_dylib.h:
##########
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file orcjit_dylib.h
+ * \brief LLVM ORC JIT DynamicLibrary (JITDylib) wrapper
+ */
+#ifndef TVM_FFI_ORCJIT_ORCJIT_DYLIB_H_
+#define TVM_FFI_ORCJIT_ORCJIT_DYLIB_H_
+
+#include <llvm/ExecutionEngine/Orc/LLJIT.h>
+#include <tvm/ffi/container/array.h>
+#include <tvm/ffi/extra/module.h>
+#include <tvm/ffi/object.h>
+#include <tvm/ffi/string.h>
+
+#include "orcjit_session.h"
+
+namespace tvm {
+namespace ffi {
+namespace orcjit {
+
+class ORCJITExecutionSession;
+
+class ORCJITDynamicLibraryObj : public ModuleObj {
+ public:
+  /*!
+   * \brief Constructor
+   * \param session The parent execution session
+   * \param dylib The LLVM JITDylib
+   * \param jit The LLJIT instance
+   * \param name The library name
+   */
+  ORCJITDynamicLibraryObj(ORCJITExecutionSession session, llvm::orc::JITDylib* 
dylib,
+                          llvm::orc::LLJIT* jit, String name);
+
+  ~ORCJITDynamicLibraryObj();
+
+  const char* kind() const final { return "orcjit"; }
+
+  Optional<Function> GetFunction(const String& name) override;
+
+ private:
+  /*!
+   * \brief Add an object file to this library
+   * \param path Path to the object file to load
+   */
+  void AddObjectFile(const String& path);
+
+  /*!
+   * \brief Set the link order for symbol resolution
+   * \param dylibs Vector of libraries to search for symbols (in order)
+   *
+   * When resolving symbols, this library will search in the specified 
libraries
+   * in the order provided. This replaces any previous link order.
+   */
+  void SetLinkOrder(const std::vector<llvm::orc::JITDylib*>& dylibs);
+
+  /*!
+   * \brief Look up a symbol in this library
+   * \param name The symbol name to look up
+   * \return Pointer to the symbol, or nullptr if not found
+   */
+  void* GetSymbol(const String& name);
+
+  /*!
+   * \brief Get the underlying LLVM JITDylib
+   * \return Reference to the LLVM JITDylib
+   */
+  llvm::orc::JITDylib& GetJITDylib();
+
+  /*!
+   * \brief Get the name of this library
+   * \return The library name
+   */
+  String GetName() const { return name_; }
+
+  /*! \brief Parent execution session (for lifetime management) */
+  ORCJITExecutionSession session_;
+
+  /*! \brief The LLVM JITDylib */
+  llvm::orc::JITDylib* dylib_;
+
+  /*! \brief The LLJIT instance (for addObjectFile API) */
+  llvm::orc::LLJIT* jit_;

Review Comment:
   From what I learned, the LLJIT is a wrapper even higher than orcjit 
execution session. Maybe it's better to put this to the session and call the 
`addObjectFile` API indirectly (via `session_`).



##########
addons/tvm-ffi-orcjit/scripts/install_llvm.ps1:
##########
@@ -0,0 +1,98 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Install LLVM from conda-forge using micromamba (Windows).
+# Usage: powershell -ExecutionPolicy Bypass -File scripts/install_llvm.ps1 
[version]
+#   version defaults to LLVM_VERSION env var, then 22.1.0
+
+param(

Review Comment:
   do the users need to install llvm or llvm is only needed when we build the 
`tvm-ffi-orcjit` package?



##########
addons/tvm-ffi-orcjit/src/ffi/orcjit_dylib.cc:
##########
@@ -0,0 +1,207 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*!
+ * \file orcjit_dylib.cc
+ * \brief LLVM ORC JIT DynamicLibrary implementation
+ */
+
+#include "orcjit_dylib.h"
+
+#include <llvm/ExecutionEngine/Orc/Core.h>
+#include <llvm/ExecutionEngine/Orc/LLJIT.h>
+#include <llvm/Object/ObjectFile.h>
+#include <llvm/Support/Error.h>
+#include <llvm/Support/MemoryBuffer.h>
+#include <tvm/ffi/c_api.h>
+#include <tvm/ffi/cast.h>
+#include <tvm/ffi/container/array.h>
+#include <tvm/ffi/error.h>
+#include <tvm/ffi/extra/c_env_api.h>
+#include <tvm/ffi/extra/module.h>
+#include <tvm/ffi/function.h>
+#include <tvm/ffi/reflection/registry.h>
+
+#include "orcjit_session.h"
+#include "orcjit_utils.h"
+
+namespace tvm {
+namespace ffi {
+namespace orcjit {
+
+ORCJITDynamicLibraryObj::ORCJITDynamicLibraryObj(ORCJITExecutionSession 
session,
+                                                 llvm::orc::JITDylib* dylib, 
llvm::orc::LLJIT* jit,
+                                                 String name)
+    : session_(std::move(session)), dylib_(dylib), jit_(jit), 
name_(std::move(name)) {
+  if (void** ctx_addr = 
reinterpret_cast<void**>(GetSymbol(ffi::symbol::tvm_ffi_library_ctx))) {
+    *ctx_addr = this;
+  }
+  Module::VisitContextSymbols([this](const ffi::String& name, void* symbol) {
+    if (void** ctx_addr = 
reinterpret_cast<void**>(GetSymbol(ffi::symbol::tvm_ffi_library_ctx))) {

Review Comment:
   ```suggestion
       if (void** ctx_addr = reinterpret_cast<void**>(GetSymbol(name.c_str()))) 
{
   ```
   typo?



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

To unsubscribe, e-mail: [email protected]

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


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


Reply via email to