跳到主要内容

MethodOverloadResolver 实现

Il2Cpp: marshal/MethodOverloadResolver.cpp Mono: Phase 3 Emit/ + 计划中的 managed resolver(语义对齐) 规范权威: ../../spec/04-METHOD-OVERLOAD.md — 本文只描述 runtime 数据结构与 C++ 落点


1. 调用链

  1. Lua 调用 dispatch closure(非 direct method closure)。
  2. Dispatch closure upvalue 携带 MethodGroups*MetaBinding::CreateMethodDispatchClosureRef)。
  3. MethodOverloadResolver::Resolve(L, groups, argStart, argCount) 返回唯一 MethodMarshalCtx* 或报错。
  4. MethodBridge::InvokeLua2Cs(L, target, argStart, ctx) 执行选中重载。

Direct closure(单重重载)经过 Resolver。


2. MethodGroups 桶结构

定义于 MarshalDefs.h

constexpr size_t kMaxSmallArgCount = 4;

struct MethodGroup {
const MethodMarshalCtx** methods;
size_t methodCount;
};

struct MethodGroups {
const MethodGroup* smallArgCountMethodGroups[kMaxSmallArgCount + 1];
const MethodMarshalCtx** largeArgCountMethods;
size_t largeArgCountMethodCount;
};

绑定期分桶: 按方法的 Lua 实参槽范围 分组。无默认参数时键为 luaArity;有尾部默认时须覆盖 minLuaArity … luaArity 各桶(或等价地放入可被 Resolve 扫到的集合),以便省略默认实参时仍能命中。Resolve 时先 O(1) 取 groups->smallArgCountMethodGroups[argCount],再必要时查 largeArgCountMethods

同一 argCount 桶内顺序 = Codegen 声明顺序(spec §3.2 tie-break 用)。候选另须满足 GetMinLuaArity(ctx) ≤ argCount ≤ ctx->luaArity


3. ConversionKind 与 Better Match

enum class ConversionKind : uint8_t {
None, Identity, ImplicitNumeric, ImplicitEnum, NullLiteral,
ImplicitReference, ImplicitExtendedInteger, ImplicitBoxing,
ImplicitArray, NotConvertible,
};

struct MethodOverloadResolutionResult {
MethodOverloadResolutionKind kind; // None / BestMatch / Ambiguous
const MethodMarshalCtx* method;
};

GetConversionKind(L, stackIndex, paramMeta)MethodOverloadResolver.cpp):

  • 读 Lua 栈类型 + MarshalMetaInfo 的目标 Il2CppType*
  • 返回该实参到形参的转换类别;
  • 与 spec §3.3 / §3.6 better function member 规则一致(Identity 优于 ImplicitBoxing 等)。

逐参比较: 对桶内每个 candidate 检查 applicability;在 applicable 集合中选最优;同分用声明顺序。


4. Resolve 算法概要

MethodOverloadResolutionResult MethodOverloadResolver::Resolve(
lua_State* L, const MethodGroups* groups, int32_t argStart, int32_t argCount)
{
// 1. 按 argCount 取桶(small / large);候选须满足
// GetMinLuaArity(ctx) ≤ argCount ≤ ctx->luaArity(尾部 C# 默认 → MethodDefaultArgs)
// 2. 遍历 methods[]:
// - 逐 CLR 形参打分;槽不足且 ParamHasCachedDefault → optionalUsed++
// - NotConvertible → 跳过
// - 更新 best:更好 ConversionKind/score,或同分下 optionalUsed 更小
// 3. BestMatch → 返回 method;Ambiguous / None → 上层 ThrowFormat
}

错误消息前缀 zlua:,与 Mono 目标一致(spec §3.5 / §7)。默认参数语义见 ../../spec/04-METHOD-OVERLOAD.md §3.3。


5. 与 MethodMarshalCtx 的配合

每个候选重载在 Bind 期已有独立 MethodMarshalCtx(含 paramsMeta[]retMetalua2CsInvoker stub;有尾部默认时另挂 MethodDefaultArgs*)。

Resolver 只选 ctx,不重新 marshal;选中后:

MethodBridge::InvokeLua2Cs(L, target, argStart, ctx);

有默认参数时,Invoke 路径对未提供的尾部形参写入 Bind 期缓存的默认槽。

虚调:MetadataUtil::ResolveInvokeMethod(ctx->method, target, ctx->sealed)InvokeLua2Cs 内处理。


6. 构造 overload

类型 SMT.__call 使用同一 MethodGroups / Resolver 机制,ctx 来自 .ctor 重载集合(TypeBinding::ctorGroups),argStart 跳过类型表 this(静态构造无 this)。

Mono Phase 3:ConstructorEmitter 已替换 ConstructorNotReady;当前按 arity 先到先得,完整 better-member Resolver 仍待接入。


7. 全签名键、别名、register_method 与 Resolver

规范:

来源撞名策略
Bind 期默认名 + [LuaAlias]允许;按最终名聚合进 MethodGroups
Bind 期同名多候选默认名 → dispatch;每个候选再挂全签名键 Name(Types…) → direct
运行时 register_method禁止占用已有 method / overload / 全签名键名;仅空位挂 direct(短名 + 冒号)
机制实现落点
单候选 → direct closureMetaBinding::CreateDirectMethodClosureRef
多候选 → dispatchCreateMethodDispatchClosureRef → Resolver
全签名键Bind 期写入与候选一一对应的 direct 键
[LuaAlias]Bind 期并入对应最终名的 MethodGroups
register_method名已存在 → error;否则写入 method map / 索引表(direct closure)

别名键仅在该最终名 只有一个候选 时为 O(1) direct;Bind 期撞名则走 Resolver。全签名键始终为对应候选的 direct。


8. 已知限制(代码现状)

状态
byref 参数GetConversionKindFIXME: handle byref;当前仅 lightuserdata Identity
静态 generic methodInvokeMethodDirectGeneric → 显式 error
[LuaMarshalAs(ParamsTable)](已移除;params 仅单槽同 szarray)

实现或修复时须同步更新 spec 测试与 Mono Emit。


9. Mono 对齐计划

Phase 3 Emit 将为多重载方法生成:

  1. dispatch Lua/C# closure(捕获 MethodGroups 等价结构);
  2. managed MethodOverloadResolver.Resolve(镜像 ConversionKind 枚举与比较规则);
  3. 选中后跳转到 该重载专用 Emit bridge(非 Method.Invoke)。

验收:与 Il2Cpp 对同一 Lua 调用选中相同重载(含 tie-break)。


10. 相关文件

文件职责
marshal/MethodOverloadResolver.cpp/.hResolve、GetConversionKind
marshal/MarshalDefs.hMethodGroups、ConversionKind
mt/MetaBinding.cpp构建 groups、dispatch closure
bridge/MethodBridge.cppInvokeLua2Cs
Editor/CppCodeGen/AotMethodAnalyzer.cs构建期重载元数据顺序

规范详述:../../spec/04-METHOD-OVERLOAD.md