Skip to main content

Il2Cpp Implementation Map

Editable source root: build-win64/Il2CppOutputProject/IL2CPP/libil2cpp/zlua In-package mirror (manual sync; do not edit directly): Packages/com.code-philosophy.zlua/ZLua~/libil2cpp-2022/zlua Lua-visible semantics: ../spec/ — this doc only covers C++ module layout, init order, and file responsibilities.

1. Module map

The Il2Cpp runtime splits into seven top-level directories, aligned 1:1 with rewritten Mono Runtime/Mono/ (see MONO.md §2).

zlua/
├── lvm/ Host lifetime, Lua state, ZLuaLib, InternalCall, Loader
├── mt/ Type registration, metatable binding, member index (`Dispatch*` + `MetaBinding`)
├── marshal/ Push/Pop, Registry, MarshalMeta, Overload resolution
├── bridge/ Method / Property / Field / Delegate call bodies
├── generated/ Build-time Codegen output (stub tables, BuiltinScripts.inc)
├── utils/ Cross-cutting: MetadataUtil, exceptions, stack guard, allocators
├── ZLuaCommon.* Shared headers, macro gates, ABI with Lua VM
└── LuaConsts.h Metatable field names, userdata kind constants

Dependency direction (hard constraint):

  • marshal/ must not #include mt/ (Mt via MetatableHooks callbacks or upper assembly).
  • bridge/ may depend on marshal/ and generated/; mt/ calls bridge/ and MarshalMeta at bind time.
  • generated/ is referenced only by lvm/ and bridge/; it does not participate in runtime logic branches.

2. Initialization order

2.1 AppDomain level (lvm/LuaAppDomain.cpp)

After the Player process enters Il2Cpp, managed code calls LuaAppDomain::Initialize() in fixed order:

StepCallResponsibility
1LuaMetadataAlloc::Initialize()Bind-time metadata heap (MethodMarshalCtx, MarshalMetaInfo, etc.)
2MetadataUtil::Initialize()Assembly / type / method resolution caches
3PropertyBridge::Initialize()Load getter/setter function table from generated/PropertyBridgeStub.h
4MethodBridge::Initialize()Load lua2CsInvoker table from generated/MethodBridgeStub.h
5DelegateBridge::Initialize()Load generated/DelegateBridgeStub.h
6LuaInternalCalls::RegisterCoreInternalCalls()Core InternalCalls
7LuaLoader::RegisterRoots()StreamingAssets / module search roots
8LuaEnv::Initialize()Create lua_State and finish Lua-side bootstrap (next section)

Optional: LuaAppDomain::InitializeFromManaged(Il2CppDelegate*) injects a managed moduleLoader delegate after step 8.

2.2 Lua state level (lvm/LuaEnv.cpp)

LuaEnv::Initialize() runs on a single global lua_State*:

StepCallResponsibility
1luaL_newstate()Allocate VM
2RegisterGlobals()__ZLUA_IL2CPP_PLAYER__=true; embed globals.lua (generated/BuiltinScripts.inc); cache __zluaErrorHandler ref
3RegisterLibs()luaL_openlibs; redirect print → Unity Debug.Log; ZLuaLib::RegisterGlobals + embed zlualib.lua
4ObjectRegistry::Initialize(L)ByObj weak cache table + slot strong-ref table
5StructRegistry::Initialize(L)non-blittable ByVal GC root registration
6MetaTableCache::Initialize(L)Type metatable registry cache
7LuaLoader::InstallHooks()package.searchers / custom loader
8AssemblyRegistry::InitializeCSharpRoot(L)Attach csharp root table; deferred type-bind entry

Host Reset: Public API is LuaAppDomain.Reset(loader) (schedule → real work at EndOfFrame). When applied: internal LuaEnv::Shutdown + Initialize again per §2.2 and install the new loader. Process-level Bridge / XML / MetadataUtil / InternalCall are not unloaded by Reset. Calling managed Initialize again when already initialized → throws.

Internal Shutdown (LuaEnv::Shutdown) releases in reverse order: ProcessPendingRefReleasesMetaTableCacheStructRegistryObjectRegistryLuaGlobalRefs::Clear → release error handler ref → lua_closeLuaLoader::Clear. The host surface does not expose Shutdown.

3. File → responsibility table

3.1 lvm/

FileResponsibility
LuaAppDomain.cpp/.hIl2Cpp entry: Initialize / InitializeFromManaged / internal Shutdown; managed Reset is scheduled via the frame pump
LuaEnv.cpp/.hGlobal lua_State, globals/libs registration, error handler, dostring, pending ref queue
ZLuaLib.cppC API: zlua.import_type, zlua.cast, zlua.box, etc. (semantics: ../spec/05-LIB.md)
LuaInternalCalls.cpp/.hInternalCall registration
LuaGlobalRefs.cpp/.hCentralized registry strong refs
LuaLoader.cpp/.hModule search, StreamingAssets loader, managed delegate loader

3.2 mt/

FileResponsibility
AssemblyRegistry.cpp/.hcsharp root; assembly scan triggered by import_type
TypeRegistry.cpp/.hType façade dispatch entry (reference / valuetype / array / enum)
TypeRegistryCommon.cpp/.hShared: type-table fields, IMT/SMT fill, Dispatch* attach
TypeRegistryReference.cpp/.hclass / interface / delegate binding
TypeRegistryValueType.cpp/.hstruct / Nullable binding
TypeRegistryArray.cpp/.hArray types, __len
MetaBinding.cpp/.hBind-time scan of public members → NameMetaMap; build method closure refs; overload groups
MetaTableCache.cpp/.hCache IMT/SMT registry refs by Il2CppClass*
InstanceTarget.cpp/.huserdata → this pointer / ByVal payload address resolution

3.3 marshal/

FileResponsibility
TypedMarshal.cpp/.hPush/Pop façade dispatched by Il2CppType*
MarshalMeta.cpp/.hCreate MarshalMetaInfo and writer function pointers for field/property/method params
MarshalDefs.hCore structs: MarshalMetaInfo, MethodMarshalCtx, MethodGroups, ConversionKind, etc.
ObjectRegistry.cpp/.hByObj userdata: (obj, viewKlass) weak cache + slot strong refs
StructRegistry.cpp/.hnon-blittable ByVal: GC root tracking
ObjectMarshal.cpp/.hReference-type push/pop
StructMarshal.cpp/.hValue-type ByVal/ByObj
PrimitiveMarshal.cpp/.hPrimitive R/W
StringMarshal.cpp/.hstring
ArrayMarshal.cpp/.harrays
DelegateMarshal.cpp/.hdelegate / Lua function
OpaqueValueMarshal.cpp/.hopaque / lightuserdata path
IntrinsicTypes.cpp/.hBuilt-in struct specializations (Vector2/3/4, etc.)
MethodOverloadResolver.cpp/.hRuntime overload selection (spec ../spec/04-METHOD-OVERLOAD.md)

Details: marshal/README.md.

3.4 bridge/

FileResponsibility
MethodBridge.cpp/.hResolve stub table → FnLua2CsInvoker; default alloca + writer slow path
PropertyBridge.cpp/.hproperty getter/setter stub dispatch
FieldBridge.cpp/.hField offset R/W (with FieldMarshalCtx)
DelegateBridge.cpp/.hC# delegate ↔ Lua function; C#→Lua GetFunction calls also go here
BridgeDefs.hShared bridge typedefs

3.5 generated/ (build output; do not hand-edit)

ArtifactGeneratorResponsibility
MethodBridgeStub.hMethodBridgeCodegenOne Bridge_* + lua2CsInvoker entry per AOT method
PropertyBridgeStub.hPropertyBridgdeCodegenproperty accessor stubs
DelegateBridgeStub.hDelegateBridgeCodgendelegate invoke stubs
MarshalBindings.*MarshalAsCodegen[LuaMarshalAs] extended writers
BuiltinScripts.incBuiltinScriptsCodegenEmbed globals.lua / zlualib.lua

Details: codegen/STUBS-IL2CPP.md.

3.6 utils/

FileResponsibility
MetadataUtil.cpp/.hIl2Cpp reflection: type lookup, method sealed checks, value size
LuaException.cpp/.hC++ → managed exception / Lua error
LuaUtil.cpp/.hregistry refs, strings, stack helpers
LuaStackGuard.hRAII stack balance
LuaMetadataAlloc.cpp/.hBind-time allocator
Collection.hBind-time containers such as AppendOnlyStringHashMap

4. Comparison with Mono

DimensionIl2CppMono
Member indexDispatch* + MetaBinding / TypeRegistry (INDEXER-IL2CPP.md)Lua three-table indexer (INDEXER-MONO.md)
Lua→C# bridgeCodegen stub reuse (by ReducedType signature)Emit/ per-member Expression.Compile
C#→LuaGetFunction + Delegate bridge (LuaCallInvoker)Same
EventDedicated metadata removed; add_*/remove_* are ordinary methodsSame