Skip to content

[Web] Fix static init order in WASM runtime to prevent GetKwargsObject crash#18968

Open
gnguralnick wants to merge 1 commit intoapache:mainfrom
gnguralnick:fix/wasm-static-init-order
Open

[Web] Fix static init order in WASM runtime to prevent GetKwargsObject crash#18968
gnguralnick wants to merge 1 commit intoapache:mainfrom
gnguralnick:fix/wasm-static-init-order

Conversation

@gnguralnick
Copy link
Copy Markdown
Contributor

Summary

After tvm-ffi v0.1.9 (6b39efb), ObjectDef::~ObjectDef() calls AutoRegisterInit() which eagerly resolves ffi.GetKwargsObject via GetGlobalRequired(). In the WASM build, all .cc files are #include'd into a single translation unit (wasm_runtime.cc), so __attribute__((constructor)) functions run in deterministic source order.

Runtime files like file_utils.cc, profiling.cc, and rpc_session.cc (which use ObjectDef in their static init blocks) were included before object.cc (which registers ffi.GetKwargsObject). This caused a fatal ValueError: Function ffi.GetKwargsObject not found during WASM _initialize, crashing before the module could load.

Fix: Move all tvm-ffi core includes before the runtime files so that ffi.GetKwargsObject is registered before any ObjectDef destructor needs it.

Error reproduced

ValueError: Function ffi.GetKwargsObject not found
  at $_initialize
  at callMain
  at doRun

This affects all WebGPU model compilation since the tvm-ffi bump in #18938.

Test plan

  • Compiled Qwen3.5-4B model to WASM with the reordered includes
  • Verified WASM loads and runs correctly in browser via web-llm

…t crash

After tvm-ffi v0.1.9 (6b39efb), ObjectDef::~ObjectDef() calls
AutoRegisterInit() which eagerly resolves ffi.GetKwargsObject via
GetGlobalRequired(). In the WASM build, all .cc files are #include'd
into a single translation unit (wasm_runtime.cc), so
__attribute__((constructor)) functions run in source order.

Previously, runtime files like file_utils.cc, profiling.cc, and
rpc_session.cc (which use ObjectDef in their static init blocks) were
included before object.cc (which registers ffi.GetKwargsObject). This
caused a fatal error during _initialize because the ObjectDef
destructors ran before the function they depend on was registered.

Fix: move all tvm-ffi core includes before the runtime files so that
ffi.GetKwargsObject is registered before any ObjectDef destructor
needs it.
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request reorders the #include statements in web/emcc/wasm_runtime.cc to ensure that TVM FFI core components are initialized before other runtime components, preventing static initialization failures in WASM. Feedback suggests further refining the internal order of the FFI includes by moving object.cc before other components like container.cc and function.cc to ensure the object system is fully registered before it is used by subsequent FFI modules.

Comment on lines +40 to +46
#include "3rdparty/tvm-ffi/src/ffi/backtrace.cc"
#include "3rdparty/tvm-ffi/src/ffi/container.cc"
#include "3rdparty/tvm-ffi/src/ffi/dtype.cc"
#include "3rdparty/tvm-ffi/src/ffi/error.cc"
#include "3rdparty/tvm-ffi/src/ffi/function.cc"
#include "3rdparty/tvm-ffi/src/ffi/object.cc"
#include "3rdparty/tvm-ffi/src/ffi/tensor.cc"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

To ensure robustness against static initialization order issues within the FFI core itself, object.cc should be included before other FFI components that might use the object system (such as container.cc, function.cc, or tensor.cc). Since object.cc registers ffi.GetKwargsObject, any static initialization in the subsequent files that triggers ObjectDef logic will be safe if object.cc is included first. This aligns with the logic described in the PR summary regarding the dependency on ffi.GetKwargsObject during static initialization.

Suggested change
#include "3rdparty/tvm-ffi/src/ffi/backtrace.cc"
#include "3rdparty/tvm-ffi/src/ffi/container.cc"
#include "3rdparty/tvm-ffi/src/ffi/dtype.cc"
#include "3rdparty/tvm-ffi/src/ffi/error.cc"
#include "3rdparty/tvm-ffi/src/ffi/function.cc"
#include "3rdparty/tvm-ffi/src/ffi/object.cc"
#include "3rdparty/tvm-ffi/src/ffi/tensor.cc"
#include "3rdparty/tvm-ffi/src/ffi/backtrace.cc"
#include "3rdparty/tvm-ffi/src/ffi/error.cc"
#include "3rdparty/tvm-ffi/src/ffi/object.cc"
#include "3rdparty/tvm-ffi/src/ffi/container.cc"
#include "3rdparty/tvm-ffi/src/ffi/dtype.cc"
#include "3rdparty/tvm-ffi/src/ffi/function.cc"
#include "3rdparty/tvm-ffi/src/ffi/tensor.cc"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I checked the actual static init blocks in the FFI core files: container.cc, function.cc, and tensor.cc all use GlobalDef() (not ObjectDef), and dtype.cc/error.cc have no static init blocks at all. So none of them depend on ffi.GetKwargsObject during initialization, and the ordering within the FFI core group doesn't matter for correctness. The critical ordering is FFI core before runtime files (which do use ObjectDef), which is already handled.

@gnguralnick gnguralnick marked this pull request as ready for review April 3, 2026 17:35
@akaashrp
Copy link
Copy Markdown
Contributor

akaashrp commented Apr 4, 2026

@gnguralnick I updated the behavior here: apache/tvm-ffi#519. So this should be fixed once this lands: #18967. Is this still an issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants