1910 lines
120 KiB
Plaintext
1910 lines
120 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import stdlib
|
||
import sys
|
||
import viperlib
|
||
import w32.fileio as fileio
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Handles.HandlesBase as HandlesBase
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||
import lib.Stub.StubMerger as StubMerger
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
|
||
import lib.core.Gen.CallGenBase as CallGenBase
|
||
import lib.core.Handles.ExprCallTable as ExprCallTable
|
||
|
||
|
||
# ============================================================
|
||
# CallGenCall - CallGenMixin 拆分(阶段 B):方法调用分派(含 super / 虚调用 / kwargs 名匹配)
|
||
#
|
||
# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。
|
||
# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。
|
||
# @t.NoVTable:静态绑定。
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class CallGenCall(CallGenBase.CallGenBase):
|
||
"""方法调用分派(含 super / 虚调用 / kwargs 名匹配)"""
|
||
|
||
# ============================================================
|
||
# _do_virtual_call — 通过虚表间接调用虚方法
|
||
#
|
||
# IR 模式:
|
||
# %1 = getelementptr StructTy, StructTy* %self, i32 0, i32 0 ; i8**
|
||
# %2 = load i8*, i8** %1 ; i8* (vtable ptr)
|
||
# %3 = bitcast i8* %2 to {i8*, ...}* ; vtable typed ptr
|
||
# %4 = getelementptr {i8*, ...}, {i8*, ...}* %3, i32 0, i32 N ; i8**
|
||
# %5 = load i8*, i8** %4 ; i8* (func ptr)
|
||
# %6 = bitcast i8* %5 to RetTy(Params)* ; func typed ptr
|
||
# call RetTy %6(Params %self, ...)
|
||
#
|
||
# 参数:
|
||
# args_head — 已构建好的参数链表头(self_ptr 为首节点)
|
||
# args_count — 参数总数(含 self)
|
||
# found_func — 方法对应的 Function 对象(用于推断函数签名)
|
||
# ret_ty — 返回类型
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _do_virtual_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
class_name: str,
|
||
method_name: str,
|
||
self_ptr: llvmlite.Value | t.CPtr,
|
||
args_head: llvmlite.Value | t.CPtr,
|
||
args_count: int,
|
||
found_func: llvmlite.Function | t.CPtr,
|
||
ret_ty: llvmlite.LLVMType | t.CPtr,
|
||
vtable_base: llvmlite.Value | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""通过虚表间接调用虚方法,返回 call 结果(void 方法返回 None)
|
||
|
||
vtable_base: 对象头指针(vtable 所在位置,即未调整的 obj_ptr)。
|
||
多继承 this 调整后 self_ptr 可能前移(如 obj+4 指向父类字段区),
|
||
从调整后位置读 vtable 会读到字段值 → 垃圾指针崩溃。默认 None 时
|
||
vtable_base = self_ptr(未调整场景,读对象头)。
|
||
"""
|
||
if pool is None or builder is None or class_name is None or method_name is None:
|
||
return None
|
||
if self_ptr is None or args_head is None:
|
||
return None
|
||
if vtable_base is None:
|
||
vtable_base = self_ptr
|
||
|
||
# 1. 获取结构体类型(用 find_struct_by_type 规避跨模块同名 find_struct 找错)
|
||
# 必须用 vtable_base(对象头)的类型而非 self_ptr:多继承 this 调整后
|
||
# self_ptr 已 bitcast 成父类指针(如 ColorM*),用其解析会得到父类
|
||
# vtable 布局(单槽 {i8*})→ method_index/method_count 按父类算,
|
||
# GEP 槽位错位读到别的函数(MultiInheritTest color_code 虚调用读到
|
||
# area FAILED 根因)。vtable_base 是接收者静态类型指针(vtable 所在
|
||
# 位置),其 VTableMethods 才是最终对象实际存储的完整 vtable 布局。
|
||
vc_entry: GenTypes.StructEntry | t.CPtr = None
|
||
struct_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if vtable_base is not None and vtable_base.Ty is not None:
|
||
vc_entry = self.Gen.StructGen.get_struct_type_from_value(vtable_base)
|
||
if vc_entry is not None:
|
||
# vc_entry 是 struct_ty(LLVMType),需要找 StructEntry
|
||
vc_entry = self.Gen.StructGen.find_struct_by_type(vc_entry)
|
||
if vc_entry is not None:
|
||
struct_ty = vc_entry.Ty
|
||
if struct_ty is None and self_ptr is not None and self_ptr.Ty is not None:
|
||
# fallback:vtable_base 无类型信息时退回 self_ptr(未调整场景两者一致)
|
||
vc_entry = self.Gen.StructGen.get_struct_type_from_value(self_ptr)
|
||
if vc_entry is not None:
|
||
vc_entry = self.Gen.StructGen.find_struct_by_type(vc_entry)
|
||
if vc_entry is not None:
|
||
struct_ty = vc_entry.Ty
|
||
if struct_ty is None:
|
||
struct_ty = self.Gen.StructGen.get_struct_type(class_name)
|
||
if struct_ty is None:
|
||
return None
|
||
|
||
# 2. 获取方法在虚表中的索引(用 entry 直接查找)
|
||
method_index: int = -1
|
||
if vc_entry is not None and vc_entry.VTableMethods is not None:
|
||
methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(vc_entry.VTableMethods, t.CPtr))
|
||
for mi in range(vc_entry.VTableMethodCount):
|
||
mname_addr: t.CSizeT = methods_arr[mi]
|
||
if mname_addr == 0:
|
||
continue
|
||
mname: str = (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr))
|
||
if mname is not None and string.strcmp(mname, method_name) == 0:
|
||
method_index = mi
|
||
break
|
||
else:
|
||
method_index = self.Gen.StructGen.get_vtable_method_index(class_name, method_name)
|
||
if method_index < 0:
|
||
return None
|
||
|
||
# 3. 基础类型
|
||
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
|
||
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
|
||
|
||
# 4. bitcast 到 i8** 访问 __vtable__ 字段(索引 0)
|
||
# vtable 指针总是在对象第一个字段,无需 GEP,直接 bitcast 到 i8** 即可。
|
||
# 这样即使 struct_ty 是 opaque(跨模块未加载完整定义)也能正常工作。
|
||
# 注意用 vtable_base(对象头)而非 self_ptr:多继承 this 调整后
|
||
# self_ptr 已前移,其头部不是 vtable 而是父类字段值。
|
||
vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, vtable_base, i8_ptr_ptr_ty)
|
||
if vtable_slot is None:
|
||
return None
|
||
|
||
# 5. load vtable 指针 (i8*)
|
||
vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot)
|
||
if vtable_ptr is None:
|
||
return None
|
||
|
||
# 6. 构造 vtable 类型 {i8*, i8*, ...}
|
||
method_count: int = 0
|
||
if vc_entry is not None:
|
||
method_count = vc_entry.VTableMethodCount
|
||
else:
|
||
method_count = self.Gen.StructGen.get_vtable_method_count(class_name)
|
||
if method_count <= 0:
|
||
return None
|
||
|
||
vt_first: llvmlite.ParamNode | t.CPtr = None
|
||
vt_prev: llvmlite.ParamNode | t.CPtr = None
|
||
for vi in range(method_count):
|
||
pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty)
|
||
if pn is None:
|
||
continue
|
||
if vt_first is None:
|
||
vt_first = pn
|
||
if vt_prev is not None:
|
||
llvmlite.paramnode_set_next(vt_prev, pn)
|
||
vt_prev = pn
|
||
|
||
vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first, method_count, None)
|
||
if vtable_ty is None:
|
||
return None
|
||
vtable_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vtable_ty)
|
||
|
||
# 7. bitcast i8* 到 vtable 类型指针
|
||
vtable_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, vtable_ptr, vtable_ptr_ty)
|
||
if vtable_typed is None:
|
||
return None
|
||
|
||
# 8. GEP 到方法槽位
|
||
func_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
|
||
builder, vtable_ty, i8_ptr_ty, vtable_typed, method_index)
|
||
if func_slot is None:
|
||
return None
|
||
|
||
# 9. load 函数指针 (i8*)
|
||
func_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, func_slot)
|
||
if func_i8 is None:
|
||
return None
|
||
|
||
# 10. 从 args_head 构造函数类型 RetTy(Param1, Param2, ...)
|
||
# 直接遍历 Value 链表提取参数类型,避免跨模块访问 found_func(stub 字段偏移问题)
|
||
fp_first: llvmlite.ParamNode | t.CPtr = None
|
||
fp_prev: llvmlite.ParamNode | t.CPtr = None
|
||
fp_count: int = 0
|
||
cur_val: llvmlite.Value | t.CPtr = args_head
|
||
for vi in range(args_count):
|
||
if cur_val is None:
|
||
break
|
||
cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_val)
|
||
fpn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty)
|
||
if fpn is not None:
|
||
if fp_first is None:
|
||
fp_first = fpn
|
||
if fp_prev is not None:
|
||
llvmlite.paramnode_set_next(fp_prev, fpn)
|
||
fp_prev = fpn
|
||
cur_val = llvmlite.value_get_next(cur_val)
|
||
fp_count += 1
|
||
|
||
func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, fp_count)
|
||
if func_ty is None:
|
||
return None
|
||
func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty)
|
||
|
||
# 11. bitcast i8* 到函数指针类型
|
||
func_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, func_i8, func_ptr_ty)
|
||
if func_ptr is None:
|
||
return None
|
||
|
||
# 12. 间接调用
|
||
return llvmlite.build_call_indirect(builder, func_ptr, args_head, args_count, ret_ty)
|
||
# ============================================================
|
||
# _call_method_on_ptr — 在结构体指针上调用方法
|
||
#
|
||
# 辅助函数:构造 ClassName.method_name 调用,self 指针为首个参数
|
||
# 如果该方法在虚表中,则走虚方法分发路径(间接调用)
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _call_method_on_ptr(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
class_name: str,
|
||
method_name: str,
|
||
self_ptr: llvmlite.Value | t.CPtr,
|
||
extra_args: t.CSizeT | t.CPtr,
|
||
extra_count: int,
|
||
trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""在结构体指针上调用方法,返回 call 结果(void 方法返回 None)
|
||
|
||
node: 触发本次调用的 AST 节点(如 Subscript 下标节点),用于 fatal_error
|
||
准确报告出错行号(传 None 时行号显示 0,不利于定位)。"""
|
||
if pool is None or builder is None or class_name is None or method_name is None:
|
||
return None
|
||
if self_ptr is None:
|
||
return None
|
||
|
||
# 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错)
|
||
# 用于 SHA1 查找和虚表分派
|
||
cmop_entry: GenTypes.StructEntry | t.CPtr = None
|
||
cmop_struct_ty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type_from_value(self_ptr)
|
||
if cmop_struct_ty is not None:
|
||
cmop_entry = self.Gen.StructGen.find_struct_by_type(cmop_struct_ty)
|
||
if cmop_entry is None:
|
||
cmop_entry = self.Gen.StructGen.find_struct(class_name)
|
||
# fallback: 若 cmop_struct_ty 为 None 但 entry 存在,从 entry 获取类型
|
||
# 用于跨模块调用时 self_ptr 类型信息丢失的情况
|
||
if cmop_struct_ty is None and cmop_entry is not None:
|
||
cmop_struct_ty = cmop_entry.Ty
|
||
|
||
# 构造方法查找名: ClassName.method_name
|
||
lookup_name: str = pool.alloc(128)
|
||
if lookup_name is None:
|
||
return None
|
||
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
|
||
|
||
# 查找函数(支持 SHA1 后缀匹配)
|
||
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name)
|
||
|
||
# 确定调用名
|
||
call_name: str = lookup_name
|
||
if found_func is not None:
|
||
found_name: str = llvmlite.function_get_name(found_func)
|
||
if found_name is not None:
|
||
call_name = found_name
|
||
else:
|
||
# found_func 为 None(stub 未注入):用类所属模块的 SHA1 构造调用名
|
||
# 优先从 entry 获取 SHA1(规避跨模块同名 find_struct 找错)
|
||
cls_sha1: str = None
|
||
if cmop_entry is not None:
|
||
cls_sha1 = cmop_entry.ModuleSha1
|
||
else:
|
||
cls_sha1 = self.Gen.StructGen.get_struct_sha1(class_name)
|
||
if cls_sha1 is None and trans is not None:
|
||
# fallback: 从 from_imports 查找类所属模块的 SHA1(含截断处理)
|
||
cls_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, class_name)
|
||
if cls_sha1 is None:
|
||
err_msg: str = pool.alloc(256)
|
||
if err_msg is not None:
|
||
viperlib.snprintf(err_msg, 256, "类 '%s' 方法 '%s' 找不到模块 SHA1", class_name, method_name)
|
||
self.Gen.TypeGenErr.fatal_error(node, err_msg)
|
||
self.Gen.TypeGenErr.fatal_error(node, "找不到模块 SHA1")
|
||
# 生成调用名: {cls_sha1}.{lookup_name}(Hash Namespace 单前缀)
|
||
mangled2: str = pool.alloc(string.strlen(cls_sha1) + string.strlen(lookup_name) + 2)
|
||
if mangled2 is not None:
|
||
viperlib.snprintf(mangled2, string.strlen(cls_sha1) + string.strlen(lookup_name) + 2,
|
||
"%s.%s", cls_sha1, lookup_name)
|
||
call_name = mangled2
|
||
|
||
# 确定返回类型(__before_init__ 和 __init__ 返回 void)
|
||
void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
|
||
call_ret_ty: llvmlite.LLVMType | t.CPtr = void_ty
|
||
if found_func is not None:
|
||
frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
|
||
if frt is not None:
|
||
call_ret_ty = frt
|
||
elif string.strcmp(method_name, "__getitem__") == 0 or string.strcmp(method_name, "__new__") == 0:
|
||
# fail-fast:__getitem__/__new__ 必返回指针,返回类型缺失意味着
|
||
# stub declare 损坏,静默推断会截断指针(32 位)崩溃,立即终止。
|
||
err_cm1: str = pool.alloc(256)
|
||
if err_cm1 is not None:
|
||
viperlib.snprintf(err_cm1, 256,
|
||
"方法 '%s' 返回类型无法确定(stub declare 返回类型缺失)", method_name)
|
||
self.Gen.TypeGenErr.fatal_error(node, err_cm1)
|
||
self.Gen.TypeGenErr.fatal_error(node, "方法返回类型无法确定")
|
||
else:
|
||
# found_func 为 None(跨模块调用 stub 未注入):无法从 declare 获取返回类型。
|
||
# __before_init__/__init__ 是编译器生成/约定方法(vpi stub 无条目):
|
||
# 恒返回 void(对齐 _special_method_ret_ty L3196-3198),直接固定,
|
||
# 否则走 text.ll/vpi 解析失败 → fail-fast 误报
|
||
# (CPythonTest PyLongObj() 构造:类未定义 __init__/__before_init__
|
||
# 但实例化仍生成调用 → "PyLongObj.__before_init__ 返回类型无法确定"根因)。
|
||
if string.strcmp(method_name, "__before_init__") == 0 or \
|
||
string.strcmp(method_name, "__init__") == 0:
|
||
call_ret_ty = void_ty
|
||
# __new__ 返回 Ptr(struct_ty)(构造函数返回自身指针,可推断)。
|
||
# __getitem__ 返回类型无法从 self 推断(可返回 i8* 如 HashTable.__getitem__
|
||
# -> t.CPtr,或 Ptr(JsonValue) 如 JsonValue.__getitem__)——推断 Ptr(cmop_struct_ty)
|
||
# 会与 define 返回类型不匹配,调用侧按错误类型读取返回值导致指针截断崩溃。
|
||
# fail-fast:__getitem__ 无 stub declare 立即报错,暴露依赖模块 vpi 缺失或
|
||
# 拓扑顺序错误(依赖模块未先翻译生成 vpi/text.ll)。
|
||
elif string.strcmp(method_name, "__new__") == 0:
|
||
if cmop_struct_ty is not None:
|
||
call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty)
|
||
else:
|
||
err_cm2: str = pool.alloc(256)
|
||
if err_cm2 is not None:
|
||
viperlib.snprintf(err_cm2, 256,
|
||
"方法 '%s' 的 self 结构体类型未知(字段类型退化,依赖模块未预注册?)", method_name)
|
||
self.Gen.TypeGenErr.fatal_error(node, err_cm2)
|
||
self.Gen.TypeGenErr.fatal_error(node, "self 结构体类型未知")
|
||
elif string.strcmp(method_name, "__getitem__") == 0:
|
||
err_cm3: str = pool.alloc(256)
|
||
if err_cm3 is not None:
|
||
viperlib.snprintf(err_cm3, 256,
|
||
"方法 '%s.__getitem__' 的 stub declare 未注入(依赖模块 vpi 缺失或拓扑顺序错误),无法确定返回类型",
|
||
class_name)
|
||
self.Gen.TypeGenErr.fatal_error(node, err_cm3)
|
||
self.Gen.TypeGenErr.fatal_error(node, "__getitem__ stub declare 未注入")
|
||
else:
|
||
# 其它跨模块方法(泛型特化方法必然无 stub declare):旧实现静默
|
||
# 保持 void → 幽灵 "call void @...__add__" + 调用方(如运算符
|
||
# 重载 try_operator_overload)回退原生运算双重发射 → llc invalid
|
||
# operand type for instruction(NumpyTest a+b 根因)。用 text.ll
|
||
# → vpi 精确解析返回类型(对齐 _translate_method_call L4641);
|
||
# 都失败则 fail-fast,绝不静默 void。
|
||
ret_cm: llvmlite.LLVMType | t.CPtr = None
|
||
if cls_sha1 is not None:
|
||
ret_cm = self._LookupMethodRetTyFromTextLL(
|
||
pool, cls_sha1, class_name, method_name)
|
||
if ret_cm is None and cls_sha1 is not None:
|
||
ret_cm = self._lookup_method_ret_ty_via_vpi(
|
||
pool, cls_sha1, class_name, method_name)
|
||
if ret_cm is not None:
|
||
call_ret_ty = ret_cm
|
||
else:
|
||
# Phase A 依赖 text.ll 未生成(方法定义模块尚未翻译)→ 标记重试,
|
||
# 保持默认类型继续(对齐 _translate_method_call L4760-4773 与跨模块
|
||
# 函数路径 L8167-8195 的 _deps_pending 机制;本函数同样服务 Mixin
|
||
# 跨模块方法调用,如 BuildPipeline gen.extract_module_docstrings)
|
||
# cls_sha1 为 None 同样视为依赖未就绪(pass1 定义类/祖先未注册
|
||
# 连 sha1 都取不到,对齐 _translate_method_call L4778-4785)
|
||
if cls_sha1 is None \
|
||
or (cls_sha1 is not None
|
||
and self._dep_text_ll_exists(pool, cls_sha1) == 0):
|
||
if trans is not None:
|
||
trans._deps_pending = 1
|
||
# [DEPDBG] 临时诊断:方法返回类型解析依赖未就绪即 pending 的根因(用后移除)
|
||
dbg_ms1: str = trans.ModuleSha1 if (trans is not None and trans.ModuleSha1 is not None) else "?"
|
||
stdio.printf("[DEPDBG] pending(method_ret): mod=%s cls=%s method=%s sha1=%s\n",
|
||
dbg_ms1, class_name, method_name,
|
||
cls_sha1 if cls_sha1 is not None else "none")
|
||
# 依赖未就绪:保持默认 i32(build_call(Void) 返回 None 会
|
||
# 破坏表达式翻译;pending 文件本遍不写盘,下遍重译)
|
||
call_ret_ty = llvmlite.Int32(pool)
|
||
else:
|
||
err_cm4: str = pool.alloc(256)
|
||
if err_cm4 is not None:
|
||
viperlib.snprintf(err_cm4, 256,
|
||
"方法 '%s.%s' 返回类型无法确定(text.ll/vpi 均未命中,跨模块 stub 未注入)",
|
||
class_name, method_name)
|
||
self.Gen.TypeGenErr.fatal_error(node, err_cm4)
|
||
self.Gen.TypeGenErr.fatal_error(node, "方法返回类型无法确定")
|
||
|
||
# 构建参数链表: self_ptr → extra_args...
|
||
llvmlite.value_set_next(self_ptr, None)
|
||
head: llvmlite.Value | t.CPtr = self_ptr
|
||
tail: llvmlite.Value | t.CPtr = self_ptr
|
||
|
||
if extra_args is not None and extra_count > 0:
|
||
for ei in range(extra_count):
|
||
arg_addr: t.CSizeT = extra_args[ei]
|
||
if arg_addr == 0:
|
||
continue
|
||
av: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(arg_addr, t.CPtr))
|
||
if av is not None:
|
||
llvmlite.value_set_next(av, None)
|
||
llvmlite.value_set_next(tail, av)
|
||
tail = av
|
||
|
||
total_count: int = 1 + extra_count
|
||
|
||
# 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数
|
||
# 优先用函数定义的默认值,无默认值时用零值兜底
|
||
# 查找函数的 defaults 信息
|
||
mdf_defaults: t.CVoid | t.CPtr = None
|
||
mdf_default_count: int = 0
|
||
mdf_param_count: int = 0
|
||
if trans is not None and trans._funcs is not None:
|
||
mdf_entry: GenTypes.FuncEntry | t.CPtr = ExprCallTable.find_func_entry_in_table(
|
||
trans._funcs, trans._func_count, lookup_name)
|
||
if mdf_entry is not None:
|
||
mdf_defaults = mdf_entry.Defaults
|
||
mdf_default_count = mdf_entry.DefaultCount
|
||
mdf_param_count = mdf_entry.ParamCount
|
||
# 全局默认参数表查询无条件执行:mdf_entry 命中时(泛型特化方法注册进
|
||
# 调用方函数表)Defaults 非 None 会短路跳过,但下方"用快照重建默认值"
|
||
# 分支依赖 mdf_gd(唯一持有 stdlib 常量快照处)——缺它必 fatal_error
|
||
# (ListTest list[int].__new__ 根因)
|
||
mdf_gd: GenTypes.FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(lookup_name)
|
||
if mdf_defaults is None and mdf_gd is not None:
|
||
mdf_defaults = mdf_gd.Defaults
|
||
mdf_default_count = mdf_gd.DefaultCount
|
||
mdf_param_count = mdf_gd.ParamCount
|
||
|
||
# 跨模块 stub 未注入兜底(同 _translate_method_call):found_func 为
|
||
# None 且函数表无 ParamCount 时,用 vpi 文本缓存补全参数数,默认
|
||
# 参数填充(含零值兜底)随即生效,declare/call 与 define 对齐。
|
||
vpi_pa: str = None
|
||
if mdf_param_count == 0 and found_func is None:
|
||
vpi_sha1_p: str = None
|
||
if cmop_entry is not None and cmop_entry.ModuleSha1 is not None:
|
||
vpi_sha1_p = cmop_entry.ModuleSha1
|
||
else:
|
||
vpi_sha1_p = self.Gen.StructGen.get_struct_sha1(class_name)
|
||
if vpi_sha1_p is not None:
|
||
vpi_pa = self.Gen.CallGenBase._vpi_method_param_annot(
|
||
pool, vpi_sha1_p, class_name, method_name)
|
||
if vpi_pa is not None and vpi_pa[0] != '\0':
|
||
vpi_pc2: int = 1
|
||
vi2: t.CSizeT = 0
|
||
while vpi_pa[vi2] != '\0':
|
||
if vpi_pa[vi2] == '@':
|
||
vpi_pc2 += 1
|
||
vi2 += 1
|
||
mdf_param_count = vpi_pc2 - 1 # 非 self 参数数
|
||
|
||
# [修复 2026-08-25] found_func 参数数回退(同 _translate_method_call):
|
||
# 函数表/默认表无 ParamCount 但 found_func(declare)已找到时用其参数数
|
||
# 作补全基准,否则省略默认参数(如 translate_value 的 target_ty=None)
|
||
# 的调用补全不触发 → call 实参 < define 形参 → ABI 错位读栈残留垃圾。
|
||
# 排除 EH 输出参数(%__eh_msg_out__/%__eh_code_out__):含 raise 函数
|
||
# 定义尾部注入 2 个 EH 形参,计入会让 _emit_eh_guarded_call 追加真实
|
||
# EH 实参前先补 zeroinitializer 占位 → 双重注入 call 实参多 2(TestFBProject
|
||
# raise_disk() 崩溃根因,与 CallGenMixin 零值兜底同源)。
|
||
if mdf_param_count == 0 and found_func is not None:
|
||
ppcnt_f2: int = 0
|
||
ppn_f2: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
while ppn_f2 is not None:
|
||
fp_nm_f2: str = llvmlite.param_get_name(ppn_f2)
|
||
if fp_nm_f2 is None or (string.strcmp(fp_nm_f2, "%__eh_msg_out__") != 0
|
||
and string.strcmp(fp_nm_f2, "%__eh_code_out__") != 0):
|
||
ppcnt_f2 += 1
|
||
ppn_f2 = llvmlite.param_get_next(ppn_f2)
|
||
if ppcnt_f2 > 1:
|
||
mdf_param_count = ppcnt_f2 - 1 # 非 self 非 EH 参数数
|
||
|
||
# 计算需要填充的参数(不含 self)
|
||
# extra_count = 已提供的非 self 参数数量
|
||
# mdf_param_count = 函数定义的非 self 参数数量
|
||
if mdf_param_count > extra_count:
|
||
mdf_offset: int = mdf_param_count - mdf_default_count
|
||
mdf_pi: int = extra_count
|
||
while mdf_pi < mdf_param_count:
|
||
# 优先用默认值
|
||
if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset:
|
||
mdf_di: int = mdf_pi - mdf_offset
|
||
if mdf_di < mdf_default_count:
|
||
# 用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收,
|
||
# 直接回退读 AST 会 use-after-free——快照失败时 fail-fast 暴露,绝不读悬空 AST)
|
||
mdf_val: llvmlite.Value | t.CPtr = None
|
||
if mdf_gd is not None:
|
||
mdf_val = self.Gen.CallGenLeafKit._build_const_from_snapshot(
|
||
pool, mod, mdf_gd, mdf_di, trans, builder)
|
||
if mdf_val is None:
|
||
# 用 node(本函数报错行号节点,如构造实参/源码 Call)而非 cl——
|
||
# cl 在本函数未定义(无该参数),读取垃圾指针导致 fatal_error
|
||
# 显示 "line 0"(FileIoTest File.__init__ 报错行号丢失根因)
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
node,
|
||
f"跨模块默认参数无法重建(快照缺失,默认值需为简单常量): {lookup_name}",
|
||
"TypeError")
|
||
continue
|
||
llvmlite.value_set_next(mdf_val, None)
|
||
llvmlite.value_set_next(tail, mdf_val)
|
||
tail = mdf_val
|
||
total_count += 1
|
||
mdf_pi += 1
|
||
continue
|
||
# 无默认值时用零值兜底(需要 found_func 获取参数类型)。
|
||
# 默认参数表按裸名注册(如 "__init__"),跨模块 "ClassName.method"
|
||
# 查找常查不到——查不到 ≠ 无默认值(如 Buf.__init__(data, capacity)
|
||
# 缺的 length=0/owned=False 恰为零值),零值兜底语义一致。
|
||
if found_func is not None:
|
||
param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
skip_z: int = 0
|
||
while skip_z <= mdf_pi and param_node_z is not None:
|
||
param_node_z = llvmlite.param_get_next(param_node_z)
|
||
skip_z += 1
|
||
if param_node_z is not None:
|
||
zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z)
|
||
zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty)
|
||
if zero_val is not None:
|
||
llvmlite.value_set_next(zero_val, None)
|
||
llvmlite.value_set_next(tail, zero_val)
|
||
tail = zero_val
|
||
total_count += 1
|
||
elif vpi_pa is not None:
|
||
# found_func 为 None(stub 未注入):用 vpi 参数注解解析
|
||
# 缺失参数类型(段索引 mdf_pi+1,跳过首参 self 空段),
|
||
# 值取类型零值(默认参数值恰为零值;查不到 ≠ 无默认值)。
|
||
seg_idx_v: int = mdf_pi + 1
|
||
seg_no_v: int = 0
|
||
seg_cur_v: t.CSizeT = 0
|
||
while seg_no_v < seg_idx_v and vpi_pa[seg_cur_v] != '\0':
|
||
if vpi_pa[seg_cur_v] == '@':
|
||
seg_no_v += 1
|
||
seg_cur_v += 1
|
||
seg_start_v: t.CSizeT = seg_cur_v
|
||
seg_len_v: t.CSizeT = 0
|
||
while vpi_pa[seg_start_v + seg_len_v] != '\0' \
|
||
and vpi_pa[seg_start_v + seg_len_v] != '@':
|
||
seg_len_v += 1
|
||
if seg_no_v == seg_idx_v:
|
||
pty_v: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
if seg_len_v > 0:
|
||
seg_buf_v: bytes = stdlib.malloc(seg_len_v + 1)
|
||
if seg_buf_v is not None:
|
||
string.strncpy(seg_buf_v, vpi_pa + seg_start_v, seg_len_v)
|
||
seg_buf_v[seg_len_v] = '\0'
|
||
rty_v: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenBase._vpi_resolve_param_annot_ty(
|
||
pool, seg_buf_v)
|
||
if rty_v is not None:
|
||
pty_v = rty_v
|
||
stdlib.free(seg_buf_v)
|
||
zero_val_v: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, pty_v)
|
||
if zero_val_v is not None:
|
||
llvmlite.value_set_next(zero_val_v, None)
|
||
llvmlite.value_set_next(tail, zero_val_v)
|
||
tail = zero_val_v
|
||
total_count += 1
|
||
mdf_pi += 1
|
||
elif found_func is not None:
|
||
# 无默认参数信息但有 found_func:用零值兜底填充缺失参数
|
||
# (原逻辑;禁止 fail-fast 误杀——同上,查不到默认参数表 ≠ 无默认值)
|
||
param_node: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
skip_idx: int = 0
|
||
while skip_idx < total_count and param_node is not None:
|
||
param_node = llvmlite.param_get_next(param_node)
|
||
skip_idx += 1
|
||
while param_node is not None:
|
||
missing_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node)
|
||
zero_val2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, missing_ty)
|
||
if zero_val2 is not None:
|
||
llvmlite.value_set_next(zero_val2, None)
|
||
llvmlite.value_set_next(tail, zero_val2)
|
||
tail = zero_val2
|
||
total_count += 1
|
||
param_node = llvmlite.param_get_next(param_node)
|
||
|
||
# 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(含 self)。
|
||
# 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT),
|
||
# 但 4096 字面量按 i32 传递,未提升导致运行时 size 高 32 位垃圾,
|
||
# 破坏伙伴分配器的池大小元数据(如 total=2048)引发 calloc 失败/OOM。
|
||
# self 在运算符重载路径 2(lhs 为 X|t.CPtr 联合简化的 Vec3** 对象指针)时
|
||
# 与形参 Vec3* 不匹配,需 bitcast(coerce 指针→指针生成 bitcast),
|
||
# 否则 call 参数类型与声明不一致 llc 报错。
|
||
if found_func is not None and head is not None:
|
||
pc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
pc_node: llvmlite.Value | t.CPtr = head
|
||
new_head_pc: llvmlite.Value | t.CPtr = head
|
||
prev_pc: llvmlite.Value | t.CPtr = None
|
||
while pc_node is not None:
|
||
pc_next_save: llvmlite.Value | t.CPtr = pc_node.Next
|
||
coerced_pc: llvmlite.Value | t.CPtr = pc_node
|
||
if pc_param is not None:
|
||
pty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pc_param)
|
||
if pty_pc is not None:
|
||
c_pc: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, pc_node, pty_pc, None)
|
||
if c_pc is not None:
|
||
coerced_pc = c_pc
|
||
pc_param = llvmlite.param_get_next(pc_param)
|
||
coerced_pc.Next = None
|
||
if prev_pc is None:
|
||
new_head_pc = coerced_pc
|
||
else:
|
||
prev_pc.Next = coerced_pc
|
||
prev_pc = coerced_pc
|
||
pc_node = pc_next_save
|
||
head = new_head_pc
|
||
|
||
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用
|
||
# 复用前面已获取的 cmop_entry(find_struct_by_type 规避跨模块同名找错)
|
||
if found_func is not None:
|
||
cmop_has_vt: int = 0
|
||
cmop_method_idx: int = -1
|
||
if cmop_entry is not None:
|
||
cmop_has_vt = cmop_entry.HasVTable
|
||
if cmop_has_vt == 1 and cmop_entry.VTableMethods is not None:
|
||
cmop_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(cmop_entry.VTableMethods, t.CPtr))
|
||
for cmop_mi in range(cmop_entry.VTableMethodCount):
|
||
cmop_mname_addr: t.CSizeT = cmop_methods_arr[cmop_mi]
|
||
if cmop_mname_addr == 0:
|
||
continue
|
||
cmop_mname: str = (str | t.CPtr)(t.CVoid(cmop_mname_addr, t.CPtr))
|
||
if cmop_mname is not None and string.strcmp(cmop_mname, method_name) == 0:
|
||
cmop_method_idx = cmop_mi
|
||
break
|
||
if cmop_has_vt == 1 and cmop_method_idx >= 0:
|
||
return self._do_virtual_call(pool, builder, mod, class_name, method_name,
|
||
self_ptr, head, total_count, found_func, call_ret_ty)
|
||
# 防御:返回类型为 i0(0 位整数)时 fail-fast,绝不输出非法 IR。
|
||
# 根因已修(gen_done 成功后不再读未初始化的 looked_up_ty,见 L3970);
|
||
# 此兜底防止未来任何路径产出零值 LLVMType 导致 llc
|
||
# "bitwidth for integer type out of range"。
|
||
if call_ret_ty is not None:
|
||
cd_i0: int = 0
|
||
match call_ret_ty:
|
||
case llvmlite.LLVMType.Int(bits):
|
||
if bits == 0:
|
||
cd_i0 = 1
|
||
case _:
|
||
pass
|
||
if cd_i0 != 0:
|
||
call_ret_ty = self._fail_method_ret_ty(method_name, node)
|
||
# 跨模块调用(found_func 为 None):创建 declare 声明,避免 llc 报 undefined value
|
||
if found_func is None:
|
||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count)
|
||
# [根治] declare 创建后按形参类型 coerce 实参(与上方 found_func 路径
|
||
# 的 L588-611 同逻辑,缺失导致字面量 0=i32 传 i64 形参(t.CSizeT)未提升:
|
||
# llc 按 i32 布局栈参(movl 4 字节写)→ i64 形参高 4 字节残留垃圾 →
|
||
# callee 读 can=[垃圾][count] 崩溃,SlotsBugTest/StringIterTest 根因,
|
||
# 反汇编 movl 实锤)。coerce 使 IR call 实参与 declare 形参类型一致。
|
||
dc_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name)
|
||
if dc_func is not None and head is not None:
|
||
dc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(dc_func)
|
||
dc_node: llvmlite.Value | t.CPtr = head
|
||
dc_new_head: llvmlite.Value | t.CPtr = head
|
||
dc_prev: llvmlite.Value | t.CPtr = None
|
||
while dc_node is not None:
|
||
dc_next: llvmlite.Value | t.CPtr = dc_node.Next
|
||
dc_cur: llvmlite.Value | t.CPtr = dc_node
|
||
if dc_param is not None:
|
||
dc_pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(dc_param)
|
||
if dc_pty is not None:
|
||
dc_c: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, dc_node, dc_pty, None)
|
||
if dc_c is not None:
|
||
dc_cur = dc_c
|
||
dc_param = llvmlite.param_get_next(dc_param)
|
||
dc_cur.Next = None
|
||
if dc_prev is None:
|
||
dc_new_head = dc_cur
|
||
else:
|
||
dc_prev.Next = dc_cur
|
||
dc_prev = dc_cur
|
||
dc_node = dc_next
|
||
head = dc_new_head
|
||
|
||
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0)
|
||
# ============================================================
|
||
# _translate_method_call - 翻译方法调用 obj.method(args)
|
||
#
|
||
# 生成: call <ret_ty> @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...)
|
||
#
|
||
# obj_ptr 是对象变量的 alloca(Ptr(StructTy)),作为 self 参数传入
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _translate_method_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
class_name: str,
|
||
method_name: str,
|
||
obj_ptr: llvmlite.Value | t.CPtr,
|
||
cl: ast.Call | t.CPtr,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""翻译方法调用,返回 call 结果 Value"""
|
||
if pool is None or builder is None or class_name is None or method_name is None:
|
||
return None
|
||
if obj_ptr is None or cl is None:
|
||
return None
|
||
|
||
# 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错)
|
||
# 用于继承链遍历、SHA1 查找和虚表分派
|
||
mc_entry: GenTypes.StructEntry | t.CPtr = None
|
||
mc_struct_ty: llvmlite.LLVMType | t.CPtr = self.Gen.StructGen.get_struct_type_from_value(obj_ptr)
|
||
if mc_struct_ty is not None:
|
||
mc_entry = self.Gen.StructGen.find_struct_by_type(mc_struct_ty)
|
||
if mc_entry is None:
|
||
mc_entry = self.Gen.StructGen.find_struct(class_name)
|
||
# [MMDBG] 诊断:mc_entry 解析(用后移除)
|
||
if string.strcmp(method_name, "Sub") == 0:
|
||
if mc_entry is not None:
|
||
stdio.printf("[MMDBG] mc_entry.Name=%s\n", mc_entry.Name)
|
||
else:
|
||
stdio.printf("[MMDBG] mc_entry=None\n")
|
||
|
||
# 构造方法查找名: ClassName.method_name
|
||
lookup_name: str = pool.alloc(128)
|
||
if lookup_name is None:
|
||
return None
|
||
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
|
||
|
||
# 查找函数(支持 SHA1 后缀匹配)
|
||
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name)
|
||
# [MMDBG] 诊断:found_func 查找(用后移除)
|
||
if string.strcmp(method_name, "Sub") == 0:
|
||
if found_func is not None:
|
||
stdio.printf("[MMDBG] found_func=%s\n", llvmlite.function_get_name(found_func))
|
||
else:
|
||
stdio.printf("[MMDBG] found_func=None lookup=%s\n", lookup_name)
|
||
|
||
# 泛型模板类方法:特化函数名带类型参数({sha1}.list[int].get),
|
||
# "ClassName.method" 短名匹配不到。特化由触发方(通常即调用方)模块完成,
|
||
# 用对象实际特化名(mc_entry.Name)构造后缀匹配,获得精确返回类型。
|
||
if found_func is None and mc_entry is not None and mc_entry.Name is not None:
|
||
if string.strcmp(mc_entry.Name, class_name) != 0:
|
||
spec_lookup: str = pool.alloc(160)
|
||
if spec_lookup is not None:
|
||
viperlib.snprintf(spec_lookup, 160, "%s.%s", mc_entry.Name, method_name)
|
||
found_func = self.find_func_in_module(mod, spec_lookup)
|
||
|
||
# 沿 MRO 祖先链查找父类方法(子类未覆盖时回退到父类,先声明父类优先)
|
||
mc_anc: str = None # 方法实际定义类(多继承 this 调整用)
|
||
if found_func is None:
|
||
mro_ptr: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||
mi: int = 1
|
||
while mro_ptr is not None and mro_ptr[mi] != 0:
|
||
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
|
||
if anc is not None:
|
||
parent_lookup: str = pool.alloc(128)
|
||
if parent_lookup is not None:
|
||
viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, method_name)
|
||
parent_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, parent_lookup)
|
||
if parent_func is not None:
|
||
found_func = parent_func
|
||
mc_anc = anc
|
||
break
|
||
mi += 1
|
||
|
||
# 兄弟 Mixin 兜底(与 TPC HandlesExprCall 一致):方法不在本类 MRO 链
|
||
# (如 BaseB 内 self.helper() 调兄弟 BaseA.helper,BaseB 无 BaseA 的
|
||
# 继承信息)。遍历已注册 struct 表找定义类方法,this 由下方
|
||
# _adjust_this_for_inherited_method 按组合布局前移 sizeof(定义类)。
|
||
# 注意:仅对普通类名兜底——泛型特化类名(list[X] / dict[K,V])是
|
||
# 模板生成的特殊容器,其特化函数(如 list[ASTptr].__getitem__)虽
|
||
# 在模块中存在,但绝非"兄弟 Mixin"(NoVTableCrossMixinTest 的
|
||
# BaseA/BaseB/Combined 场景)。若不过滤,JsonValue.__getitem__ 等
|
||
# 普通方法调用在 found_func 未命中时会误绑定到 list 特化函数,
|
||
# this 按 list 布局前移 sizeof(list) → 运行期读 -1 崩溃
|
||
# (Config.vp Load_project_config root.__getitem__ 根因)。
|
||
# 跨模块兄弟 Mixin 兜底命中记录:方法定义类在另一文件(如
|
||
# FuncGenBase._mangle_name——调用类 ClassGenVTable 不继承它),
|
||
# 本地 IR 无 define,需经候选类模块 sha1 查 text.ll 返回类型。
|
||
mixin_hit: int = 0
|
||
mixin_ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||
mixin_anc_name: str = None
|
||
mixin_anc_sha1: str = None
|
||
if found_func is None:
|
||
# 兄弟 Mixin 兜底仅对"接收者类属于当前模块"的场景适用:self 调用兄弟
|
||
# Mixin 方法时接收者是本类(与候选兄弟类同模块)。接收者类是跨模块类
|
||
# (如 self.Gen.TypeGenResolve 的 TypeGenResolve,定义在另一模块)时,
|
||
# 其方法必须经该类自身模块(text.ll/vpi)解析——若本模块恰好定义了
|
||
# 同名方法 {Cand}.{method},本兜底会误绑定:最坏情况绑定到正在编译的
|
||
# 函数自身 → ImportsGenMixin.set_current_file 内 self.Gen.TypeGenResolve.
|
||
# set_current_file(...) 被编译成自调用 → 无限递归 stack-overflow
|
||
# (二代编 FuncTest 崩溃根因)。接收者类模块无法确定时保持原行为。
|
||
sib_recv_local: int = 1
|
||
if trans is not None and trans.ModuleSha1 is not None:
|
||
sib_recv_sha1: str = None
|
||
if mc_entry is not None and mc_entry.ModuleSha1 is not None:
|
||
sib_recv_sha1 = mc_entry.ModuleSha1
|
||
else:
|
||
sib_recv_sha1 = self.Gen.StructGen.get_struct_sha1(class_name)
|
||
if sib_recv_sha1 is not None:
|
||
if string.strcmp(sib_recv_sha1, trans.ModuleSha1) != 0:
|
||
sib_recv_local = 0
|
||
if sib_recv_local != 0:
|
||
sc_i: int = 0
|
||
sc_n: int = self.Gen.StructGen.get_struct_count()
|
||
while sc_i < sc_n and found_func is None and mixin_hit == 0:
|
||
cand_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen._get_struct_entry(sc_i)
|
||
if cand_entry is not None and cand_entry.Name is not None:
|
||
cand_name: str = cand_entry.Name
|
||
if string.strcmp(cand_name, class_name) != 0:
|
||
# 泛型特化类名含 '['(list[...]/dict[...]):跳过,
|
||
# 不是兄弟 Mixin 候选(见上方注释)
|
||
if string.strchr(cand_name, '[') is not None:
|
||
sc_i += 1
|
||
continue
|
||
cand_lookup: str = pool.alloc(128)
|
||
if cand_lookup is not None:
|
||
viperlib.snprintf(cand_lookup, 128, "%s.%s", cand_name, method_name)
|
||
cand_func: llvmlite.Function | t.CPtr = self.find_func_in_module(
|
||
mod, cand_lookup)
|
||
if cand_func is not None:
|
||
found_func = cand_func
|
||
mc_anc = cand_name
|
||
else:
|
||
# 跨模块 Mixin(定义类在另一文件,本地 IR 无 define):
|
||
# 用候选类模块 sha1 查 text.ll 返回类型,命中即锁定定义类,
|
||
# 后续 ret_anc_* 据此构造 {sha1}.{class}.{method} 调用名。
|
||
# 否则 ret_anc_sha1 停在调用类自身 sha1,_dep_text_ll_exists
|
||
# 查自身 text.ll(Phase A 翻译中未生成)→ 永久 pending 死锁
|
||
# (ClassGenVTable._mangle_name → 7871cc1aabebfc33 根因)。
|
||
if mixin_hit == 0:
|
||
cand_sha1_cx: str = self.Gen.StructGen.get_struct_sha1(cand_name)
|
||
if cand_sha1_cx is not None \
|
||
and self._dep_text_ll_exists(pool, cand_sha1_cx) != 0:
|
||
cand_ret_cx: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
|
||
pool, cand_sha1_cx, cand_name, method_name)
|
||
if cand_ret_cx is not None:
|
||
mixin_hit = 1
|
||
mixin_ret_ty = cand_ret_cx
|
||
mixin_anc_name = cand_name
|
||
mixin_anc_sha1 = cand_sha1_cx
|
||
sc_i += 1
|
||
|
||
# 确定调用名(默认 "ClassName.method";found_func 未命中时沿 MRO 用
|
||
# 方法实际定义类的 SHA1 构造,如 Module.append → AST 定义的 append,
|
||
# 函数名为 {AST_sha1}.AST.append)
|
||
call_name: str = lookup_name
|
||
if found_func is not None:
|
||
found_name: str = llvmlite.function_get_name(found_func)
|
||
if found_name is not None:
|
||
call_name = found_name
|
||
|
||
# 确定返回类型
|
||
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty
|
||
if found_func is not None:
|
||
frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
|
||
if frt is not None:
|
||
call_ret_ty = frt
|
||
else:
|
||
# found_func 为 None(stub 未注入):先处理编译器内置特殊方法
|
||
sp_ty2: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name)
|
||
if sp_ty2 is not None:
|
||
call_ret_ty = sp_ty2
|
||
# 特殊方法(__before_init__ 等)跨模块调用同样需带 sha1 前缀:
|
||
# memhub.alloc_buf 显式调 buf.__before_init__(),buf 是 viperio.Buf*,
|
||
# 若用裸名 @Buf.__before_init__ 链接 undefined symbol。用
|
||
# mc_entry.ModuleSha1 / get_struct_sha1 / 类型名提取 sha1 构造
|
||
# {sha1}.Buf.__before_init__。
|
||
sp_anc_name: str = class_name
|
||
sp_anc_sha1: str = None
|
||
if mc_entry is not None:
|
||
sp_anc_sha1 = mc_entry.ModuleSha1
|
||
else:
|
||
sp_anc_sha1 = self.Gen.StructGen.get_struct_sha1(class_name)
|
||
if sp_anc_sha1 is None and mc_struct_ty is not None:
|
||
match mc_struct_ty:
|
||
case llvmlite.LLVMType.Struct(_fs_sp, _fc_sp, type_name_sp):
|
||
if type_name_sp is not None and type_name_sp[0] != '\0':
|
||
tl_sp: t.CSizeT = string.strlen(type_name_sp)
|
||
if tl_sp >= 16:
|
||
sb_sp: str = pool.alloc(17)
|
||
if sb_sp is not None:
|
||
string.strncpy(sb_sp, type_name_sp, 16)
|
||
sb_sp[16] = '\0'
|
||
sp_anc_sha1 = sb_sp
|
||
case _:
|
||
pass
|
||
if sp_anc_sha1 is not None:
|
||
ml_sp: t.CSizeT = string.strlen(sp_anc_sha1) + string.strlen(sp_anc_name) \
|
||
+ string.strlen(method_name) + 3
|
||
mangled_sp: str = pool.alloc(ml_sp)
|
||
if mangled_sp is not None:
|
||
viperlib.snprintf(mangled_sp, ml_sp, "%s.%s.%s",
|
||
sp_anc_sha1, sp_anc_name, method_name)
|
||
call_name = mangled_sp
|
||
else:
|
||
# 方法实际定义类(跨模块调用名/返回类型来源;Module.append 定义在 AST)
|
||
# 默认 class_name 自身,MRO fallback 命中祖先类时更新
|
||
ret_anc_name: str = class_name
|
||
ret_anc_sha1: str = None
|
||
if mc_entry is not None:
|
||
ret_anc_sha1 = mc_entry.ModuleSha1
|
||
else:
|
||
ret_anc_sha1 = self.Gen.StructGen.get_struct_sha1(class_name)
|
||
# 跨模块兄弟 Mixin 兜底命中:定义类锁定为候选类(如 FuncGenBase),
|
||
# 返回类型与调用名前缀以其模块 sha1 为准,避免 ret_anc_sha1 停在
|
||
# 调用类自身 sha1 → 查自身 text.ll(未生成)→ 永久 pending 死锁
|
||
if mixin_hit != 0:
|
||
ret_anc_name = mixin_anc_name
|
||
ret_anc_sha1 = mixin_anc_sha1
|
||
call_ret_ty = mixin_ret_ty
|
||
if ret_anc_sha1 is None:
|
||
# 沿 MRO 找第一个有 SHA1 的类
|
||
mro_s0: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||
mi_s0: int = 1
|
||
while mro_s0 is not None and mro_s0[mi_s0] != 0 and ret_anc_sha1 is None:
|
||
anc_s0: str = (str | t.CPtr)(t.CVoid(mro_s0[mi_s0], t.CPtr))
|
||
if anc_s0 is not None:
|
||
ret_anc_sha1 = self.Gen.StructGen.get_struct_sha1(anc_s0)
|
||
mi_s0 += 1
|
||
|
||
# 泛型特化方法调用:特化函数可能尚未注册(如 ast.base 用
|
||
# list[AST|t.CPtr].get)。主动触发特化(幂等,MethodsEmitted 防重入),
|
||
# 特化后重新查找即可命中,返回类型来自特化函数定义(天然精确)。
|
||
gen_done: int = 0
|
||
# text.ll 查找结果提升为函数级并显式初始化:gen_done==1 成功时
|
||
# 下方回退段不执行,若在此声明则读到未初始化的池内存垃圾(非 NULL),
|
||
# 把已正确解析的 call_ret_ty(特化 define 的 i32)覆盖成垃圾零值
|
||
# LLVMType → build_call 输出 call i0(llc bitwidth out of range)。
|
||
looked_up_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if class_name is not None:
|
||
lbkt_g: str = string.strchr(class_name, '[')
|
||
if lbkt_g is not None:
|
||
rbkt_g: str = string.strrchr(class_name, ']')
|
||
if rbkt_g is not None and rbkt_g > lbkt_g:
|
||
base_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_g) - t.CUInt64T(class_name))
|
||
arg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_g) - t.CUInt64T(lbkt_g) - 1)
|
||
if base_len_g > 0 and arg_len_g > 0:
|
||
base_buf_g: str = pool.alloc(base_len_g + 1)
|
||
arg_buf_g: str = pool.alloc(arg_len_g + 1)
|
||
if base_buf_g is not None and arg_buf_g is not None:
|
||
string.strncpy(base_buf_g, class_name, base_len_g)
|
||
base_buf_g[base_len_g] = '\0'
|
||
string.strncpy(arg_buf_g, lbkt_g + 1, arg_len_g)
|
||
arg_buf_g[arg_len_g] = '\0'
|
||
ta_list_g: list[str] | t.CPtr = list[str](pool, 8)
|
||
if ta_list_g is not None:
|
||
# 逗号分隔多类型实参(list[X] / dict[K, V])
|
||
cur_arg_g: str = arg_buf_g
|
||
while cur_arg_g is not None:
|
||
comma_g: str = string.strchr(cur_arg_g, ',')
|
||
if comma_g is None:
|
||
ta_list_g.append(cur_arg_g)
|
||
break
|
||
seg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(comma_g) - t.CUInt64T(cur_arg_g))
|
||
seg_buf_g: str = pool.alloc(seg_len_g + 1)
|
||
if seg_buf_g is not None:
|
||
string.strncpy(seg_buf_g, cur_arg_g, seg_len_g)
|
||
seg_buf_g[seg_len_g] = '\0'
|
||
ta_list_g.append(seg_buf_g)
|
||
cur_arg_g = comma_g + 1
|
||
# base_buf_g 可能已带模板模块 SHA1 前缀({tpl}.GSList):
|
||
# 剥离后再查模板/特化,保证 _find_generic_template 命中裸模板名。
|
||
base_clean_g: str = base_buf_g
|
||
if base_len_g > 17:
|
||
is_sha1_pfx_g: int = 1
|
||
si_g: int
|
||
for si_g in range(16):
|
||
cg_g: t.CChar = base_buf_g[si_g]
|
||
if not (('0' <= cg_g <= '9') or ('a' <= cg_g <= 'f')):
|
||
is_sha1_pfx_g = 0
|
||
break
|
||
if is_sha1_pfx_g != 0 and base_buf_g[16] == '.':
|
||
base_clean_g = base_buf_g + 17
|
||
spec_name_g: str = self.Gen.ClassGenGeneric._specialize_generic_class(
|
||
trans, base_clean_g, ta_list_g)
|
||
if spec_name_g is not None:
|
||
# 特化后重新查找特化函数(特化名 = 调用点类名)。
|
||
# find_func_in_module 后缀匹配:定义符号名
|
||
# {模板}.spec.method(Hash Namespace 单前缀),
|
||
# 同时以裸名(spec.method)和带模板前缀名
|
||
# ({tpl}.spec.method)结尾,两种 class_name 形式
|
||
# 都能命中本地 define。
|
||
spec_lk_g: str = pool.alloc(
|
||
string.strlen(class_name) + string.strlen(method_name) + 2)
|
||
if spec_lk_g is not None:
|
||
viperlib.snprintf(spec_lk_g,
|
||
string.strlen(class_name) + string.strlen(method_name) + 2,
|
||
"%s.%s", class_name, method_name)
|
||
spec_found_g: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, spec_lk_g)
|
||
if spec_found_g is not None:
|
||
frt_g: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(spec_found_g)
|
||
if frt_g is not None:
|
||
call_ret_ty = frt_g
|
||
found_func = spec_found_g
|
||
gen_done = 1
|
||
# mixin_hit:跨模块 Mixin 兜底已锁定定义类与返回类型,跳过
|
||
# text.ll/vpi/pending 重查段,直接构造 {sha1}.{class}.{method} 调用名
|
||
if gen_done == 0 and mixin_hit == 0:
|
||
# 尝试从 text.ll 查找实际返回类型
|
||
# 避免指针返回值被默认 i32 导致 inttoptr 截断
|
||
looked_up_ty = self._LookupMethodRetTyFromTextLL(
|
||
pool, ret_anc_sha1, ret_anc_name, method_name)
|
||
# 沿 MRO 祖先链重试:方法可能定义在基类(如 Module.append →
|
||
# AST.append,函数名 {ast_sha1}.AST.append,且基类在另一模块文件
|
||
# 如 ast/stmts.vp 的 Module vs ast/base.vp 的 AST),按调用类名
|
||
# 及其 sha1 查不到,需用每个祖先类的类名 + 祖先类所属模块 sha1
|
||
# 查 text.ll(NewAstTest mod.append 根因)
|
||
if looked_up_ty is None:
|
||
mro_t2: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||
mi_t2: int = 1
|
||
while mro_t2 is not None and mro_t2[mi_t2] != 0 and looked_up_ty is None:
|
||
anc_t2: str = (str | t.CPtr)(t.CVoid(mro_t2[mi_t2], t.CPtr))
|
||
if anc_t2 is not None and string.strcmp(anc_t2, class_name) != 0:
|
||
anc_sha1_t2: str = self.Gen.StructGen.get_struct_sha1(anc_t2)
|
||
looked_up_ty = self._LookupMethodRetTyFromTextLL(
|
||
pool, anc_sha1_t2, anc_t2, method_name)
|
||
if looked_up_ty is not None:
|
||
ret_anc_name = anc_t2
|
||
ret_anc_sha1 = anc_sha1_t2
|
||
mi_t2 += 1
|
||
if gen_done == 0 and looked_up_ty is not None:
|
||
call_ret_ty = looked_up_ty
|
||
elif gen_done == 0:
|
||
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
|
||
vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
|
||
pool, ret_anc_sha1, ret_anc_name, method_name)
|
||
# vpi 同样沿 MRO 祖先链重试(基类方法注解,用祖先类自身 sha1)
|
||
if vpi_ret_ty is None:
|
||
mro_v2: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||
mi_v2: int = 1
|
||
while mro_v2 is not None and mro_v2[mi_v2] != 0 and vpi_ret_ty is None:
|
||
anc_v2: str = (str | t.CPtr)(t.CVoid(mro_v2[mi_v2], t.CPtr))
|
||
if anc_v2 is not None and string.strcmp(anc_v2, class_name) != 0:
|
||
anc_sha1_v2: str = self.Gen.StructGen.get_struct_sha1(anc_v2)
|
||
vpi_ret_ty = self._lookup_method_ret_ty_via_vpi(
|
||
pool, anc_sha1_v2, anc_v2, method_name)
|
||
if vpi_ret_ty is not None:
|
||
ret_anc_name = anc_v2
|
||
ret_anc_sha1 = anc_sha1_v2
|
||
mi_v2 += 1
|
||
if vpi_ret_ty is not None:
|
||
call_ret_ty = vpi_ret_ty
|
||
else:
|
||
# Phase A 依赖 text.ll 未生成(方法定义模块尚未翻译)→ 标记
|
||
# 重试,保持默认类型继续(下遍依赖生成后可精确解析),对齐跨模块
|
||
# 函数路径 L8167-8195 的 _deps_pending 机制。BuildPipeline.vp
|
||
# L216 gen.extract_module_docstrings 根因:方法定义在
|
||
# ExprGenMixin(Mixin 模块),Phase A 顺序中 ExprGenMixin 的
|
||
# text.ll 尚未生成 → MRO 链查找全部未命中 → fail-fast 误报。
|
||
# ret_anc_sha1 为 None 同样视为依赖未就绪:pass1 中 Generator
|
||
# 及其 Mixin 全部 defer(依赖 Handles/* 未翻译)→ 结构体未注册
|
||
# → get_struct_sha1/MRO 查找全空 → 连 sha1 都取不到
|
||
# (g._register_cdefine_from_value 根因)。标记 _deps_pending
|
||
# 下遍重译,绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。
|
||
if ret_anc_sha1 is None \
|
||
or (ret_anc_sha1 is not None
|
||
and self._dep_text_ll_exists(pool, ret_anc_sha1) == 0):
|
||
if trans is not None:
|
||
trans._deps_pending = 1
|
||
# [DEPDBG] 临时诊断:方法祖先模块依赖未就绪即 pending 的根因(用后移除)
|
||
dbg_ms2: str = trans.ModuleSha1 if (trans is not None and trans.ModuleSha1 is not None) else "?"
|
||
stdio.printf("[DEPDBG] pending(mro_ret): mod=%s cls=%s method=%s ret_sha1=%s text=%d\n",
|
||
dbg_ms2, class_name, method_name,
|
||
ret_anc_sha1 if ret_anc_sha1 is not None else "none",
|
||
self._dep_text_ll_exists(pool, ret_anc_sha1) if ret_anc_sha1 is not None else -1)
|
||
# 依赖未就绪:保持默认 i32 继续而非 Void——build_call(Void)
|
||
# 返回 None,方法调用结果喂进表达式(if 条件/比较)时 fatal
|
||
# "if 条件表达式翻译失败"(ExprGenAttr._get_cderef_attr_base
|
||
# 根因)。本遍不写盘、下遍重译精确解析,错误类型不会进入
|
||
# 产物(对齐跨模块函数路径 L8167-8195"保持默认类型继续")。
|
||
call_ret_ty = llvmlite.Int32(pool)
|
||
else:
|
||
# 追加80e 断点 A:方法可能定义在 MRO 祖先(Mixin)模块。
|
||
# 此时 ret_anc_sha1 仍是调用类自身的 sha1(MRO 双路重试
|
||
# 失败未更新),且调用类(如 Generator)已注册、自身 text.ll
|
||
# 存在 → 上方 guard 不成立 → 直接 fail-fast。但 MRO 重试
|
||
# 落空可能只是"祖先定义模块未翻译"(AssignGenMixin.vp 的
|
||
# text.ll 未生成),属依赖未就绪而非方法不存在。遍历祖先链:
|
||
# 任一祖先的 sha1 取不到或其 text.ll 未生成 → 结果不确定,
|
||
# 标记 pending 下遍重试(届时祖先 text.ll 生成,MRO 重试
|
||
# 可精确解析);全部祖先就绪仍查不到才是真错误。
|
||
mro_p2: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||
mi_p2: int = 1
|
||
anc_missing_p2: int = 0
|
||
while mro_p2 is not None and mro_p2[mi_p2] != 0:
|
||
anc_p2: str = (str | t.CPtr)(t.CVoid(mro_p2[mi_p2], t.CPtr))
|
||
if anc_p2 is not None:
|
||
anc_sha1_p2: str = self.Gen.StructGen.get_struct_sha1(anc_p2)
|
||
if anc_sha1_p2 is None \
|
||
or self._dep_text_ll_exists(pool, anc_sha1_p2) == 0:
|
||
anc_missing_p2 = 1
|
||
break
|
||
mi_p2 += 1
|
||
if anc_missing_p2 != 0:
|
||
if trans is not None:
|
||
trans._deps_pending = 1
|
||
# [DEPDBG] 临时诊断:MRO 祖先模块依赖未就绪即 pending 的根因(用后移除)
|
||
dbg_ms3: str = trans.ModuleSha1 if (trans is not None and trans.ModuleSha1 is not None) else "?"
|
||
stdio.printf("[DEPDBG] pending(mro_anc): mod=%s cls=%s method=%s anc=%s anc_sha1=%s\n",
|
||
dbg_ms3, class_name, method_name,
|
||
anc_p2 if anc_p2 is not None else "none",
|
||
anc_sha1_p2 if anc_sha1_p2 is not None else "none")
|
||
# 依赖未就绪:保持默认 i32(同上,build_call(Void) 返回
|
||
# None 会破坏表达式翻译,pending 文件本遍不写盘)
|
||
call_ret_ty = llvmlite.Int32(pool)
|
||
else:
|
||
call_ret_ty = self._fail_method_ret_ty(method_name, cl)
|
||
|
||
# found_func 未命中但返回类型已解析:用方法定义类构造跨模块调用名
|
||
# (Module.append → {AST_sha1}.AST.append,避免链接 undefined reference)
|
||
if ret_anc_name is not None and ret_anc_sha1 is None:
|
||
# ret_anc_sha1 缺失(如 find_struct 未命中跨模块结构体)时,
|
||
# 从对象实际 LLVM 类型名提取 sha1 前缀:类型名形如
|
||
# "2c175afd85852faf.Buf"({sha1}.{ClassName}),前 16 字符即模块 sha1。
|
||
# 例:memhub.alloc_buf 里 buf.__before_init__(),buf 是 viperio.Buf*,
|
||
# 其类型名含 viperio 模块 sha1,借此构造 {sha1}.Buf.__before_init__,
|
||
# 避免静默生成裸名 @Buf.__before_init__(链接 undefined symbol)。
|
||
if mc_struct_ty is not None:
|
||
match mc_struct_ty:
|
||
case llvmlite.LLVMType.Struct(_fields_st, _fcount_st, type_name_st):
|
||
if type_name_st is not None and type_name_st[0] != '\0':
|
||
type_len_st: t.CSizeT = string.strlen(type_name_st)
|
||
if type_len_st >= 16:
|
||
sha1_from_ty: str = pool.alloc(17)
|
||
if sha1_from_ty is not None:
|
||
string.strncpy(sha1_from_ty, type_name_st, 16)
|
||
sha1_from_ty[16] = '\0'
|
||
ret_anc_sha1 = sha1_from_ty
|
||
case _:
|
||
pass
|
||
if ret_anc_name is not None and ret_anc_sha1 is not None:
|
||
ml_anc: t.CSizeT = string.strlen(ret_anc_sha1) + string.strlen(ret_anc_name) \
|
||
+ string.strlen(method_name) + 3
|
||
mangled_anc: str = pool.alloc(ml_anc)
|
||
if mangled_anc is not None:
|
||
viperlib.snprintf(mangled_anc, ml_anc, "%s.%s.%s",
|
||
ret_anc_sha1, ret_anc_name, method_name)
|
||
call_name = mangled_anc
|
||
# 类型名提取的 sha1 无法保证为真实模块 sha1(跨模块 stub 类型名
|
||
# 带前缀但 find_struct 未注册时仍可用),此处不校验格式
|
||
elif ret_anc_name is not None and ret_anc_sha1 is None:
|
||
# fail-fast:方法所属类既查不到 SHA1 又从类型名提取失败,
|
||
# 禁止静默裸名(否则链接期 undefined symbol 难以定位)
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
cl,
|
||
f"方法 '{method_name}' 所属类 '{ret_anc_name}' 无法解析模块 SHA1"
|
||
f"(text.ll/vpi/类型名均未命中),跨模块调用名构造失败",
|
||
"TypeError")
|
||
|
||
# 翻译调用参数
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
can: t.CSizeT = 0
|
||
if cargs is not None:
|
||
can = len(cargs)
|
||
kw_calls: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords
|
||
kwc: t.CSizeT = 0
|
||
if kw_calls is not None:
|
||
kwc = len(kw_calls)
|
||
|
||
# 多继承 this 调整(字节偏移法,2026-08-10,与 TPC HandlesExprCall._adjust_this_for_inherited_method 一致):
|
||
# 继承方法体按"定义类自身布局"读 self 字段(如 B.get_b 内 GEP(self_B, [0,1])
|
||
# 的字节偏移是 B 布局中 b 的 offset 12)。父类字段区在子类中的字节偏移可能
|
||
# 不同(如 AB={vtable,a@8,b@12} 中 b 偏移 16),self 需按字节差前移,使父类
|
||
# 方法内二次 GEP 恰好落到子类字段。
|
||
# delta = 字段在子类中字节偏移 − 字段在父类自身布局中字节偏移
|
||
# delta==0(第一父类,字段区前缀对齐)无需调整;delta>0 时按字节 GEP 到
|
||
# 父类字段区在子类中的等效基址,再 bitcast 成父类指针。
|
||
# 原实现仅覆盖"无 vtable 的父类"(其首字段偏移 0,GEP 到首字段即父类起点),
|
||
# 且用 GEP 字段法——对 vtable 父类(首字段偏移非 0,如 B)被直接跳过不调整
|
||
# → AB 场景 B.get_b 按 B 布局读 self.b@12 落到 a → AB 字段/方法 FAILED。
|
||
self_arg: llvmlite.Value | t.CPtr = obj_ptr
|
||
if mc_anc is not None and string.strcmp(mc_anc, class_name) != 0:
|
||
# 判断 mc_anc 是否为 class_name 的第一父类:第一父类字段区前缀对齐
|
||
# (delta==0)无需调整;非第一父类必须调整 self,任何一步失败都
|
||
# fail-fast——绝不静默用未调整的 obj_ptr 当 self,否则方法按自身
|
||
# 布局读字段读到垃圾(lookup_reexport strcmp 概率崩溃根因候选)。
|
||
is_first_parent_th: int = 0
|
||
mro_fp_th: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, class_name)
|
||
if mro_fp_th is not None and mro_fp_th[1] != 0:
|
||
first_parent_th: str = (str | t.CPtr)(t.CVoid(mro_fp_th[1], t.CPtr))
|
||
if first_parent_th is not None and string.strcmp(first_parent_th, mc_anc) == 0:
|
||
is_first_parent_th = 1
|
||
anc_entry_th: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(mc_anc)
|
||
# 无字段父类(FieldCount==0,如多继承中的纯方法类 Vec2Extra):
|
||
# 继承方法体按"定义类字段"读 self,定义类无字段则方法体不读
|
||
# self 布局 → this 无需字节调整,原样传入即可(对齐 TPC
|
||
# _adjust_this_for_inherited_method:anc_members 为空直接返回 ObjVal)。
|
||
if anc_entry_th is not None and anc_entry_th.FieldCount > 0:
|
||
anc_first_name_th: str = None
|
||
afi_th: int = 0
|
||
while afi_th < anc_entry_th.FieldCount:
|
||
afe_th: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry(
|
||
anc_entry_th, afi_th)
|
||
if afe_th is not None:
|
||
afn_th: str = self.Gen.StructGen.get_field_name_ptr(afe_th)
|
||
if afn_th is not None and string.strcmp(afn_th, "__vtable__") != 0:
|
||
anc_first_name_th = afn_th
|
||
break
|
||
afi_th += 1
|
||
if anc_first_name_th is not None:
|
||
sub_entry_th: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(
|
||
class_name)
|
||
if sub_entry_th is not None:
|
||
anc_field_th: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field(
|
||
anc_entry_th.Ty, anc_first_name_th)
|
||
sub_field_th: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field(
|
||
sub_entry_th.Ty, anc_first_name_th)
|
||
if anc_field_th is not None and sub_field_th is not None:
|
||
anc_off_th: int = self._field_byte_offset(
|
||
pool, anc_entry_th, anc_field_th.Index)
|
||
sub_off_th: int = self._field_byte_offset(
|
||
pool, sub_entry_th, sub_field_th.Index)
|
||
delta_th: int = sub_off_th - anc_off_th
|
||
if delta_th > 0:
|
||
i8_ty_th: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_th: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_th)
|
||
obj_i8_th: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, obj_ptr, i8_ptr_th)
|
||
delta_val_th: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, delta_th)
|
||
adj_th: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, i8_ty_th, obj_i8_th, delta_val_th)
|
||
if adj_th is not None:
|
||
anc_ptr_ty_th: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, anc_entry_th.Ty)
|
||
# 跨模块基类(如 Generator → ClassGenBase)的完整定义不在本模块,
|
||
# bitcast 引用 %"sha1.ClassGenBase" 前必须确保 opaque 声明存在,
|
||
# 否则 llc 报 "use of undefined type"(PrintModule 只扫函数签名,
|
||
# 函数体内的 bitcast 类型不会被自动声明)。
|
||
llvmlite.module_ensure_opaque_for_type(mod, pool, anc_ptr_ty_th)
|
||
self_arg = llvmlite.build_bitcast(builder, adj_th, anc_ptr_ty_th)
|
||
elif sub_field_th is None and anc_field_th is not None:
|
||
# 兄弟 Mixin 场景(对齐 TPC _adjust_this_for_inherited_method):
|
||
# 调用类(class_name=BaseB)不含定义类(mc_anc=BaseA)字段——
|
||
# BaseA 在组合类 MRO 中位于 BaseB 之前(如 Combined(BaseA, BaseB),
|
||
# BaseB 内 self.helper() 调 BaseA.helper)。BaseB.this 指向组合类中
|
||
# BaseB 字段区起点,BaseA 区在它前面,this 前移 sizeof(定义类)。
|
||
# 若无此分支,sub_field_th 查找失败 → 下方 fail-fast,兄弟 Mixin
|
||
# 调用永远编译不过(NoVTableCrossMixinTest BaseB.caller 根因)。
|
||
anc_size_th: int = self.Gen.ClassGenEnum._get_type_size(anc_entry_th.Ty)
|
||
if anc_size_th > 0:
|
||
i8_ty_th2: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_th2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_th2)
|
||
obj_i8_th2: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, obj_ptr, i8_ptr_th2)
|
||
sib_delta_th: llvmlite.Value | t.CPtr = llvmlite.const_int32(
|
||
pool, 0 - anc_size_th)
|
||
adj_th2: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, i8_ty_th2, obj_i8_th2, sib_delta_th)
|
||
if adj_th2 is not None:
|
||
anc_ptr_ty_th2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, anc_entry_th.Ty)
|
||
llvmlite.module_ensure_opaque_for_type(
|
||
mod, pool, anc_ptr_ty_th2)
|
||
self_arg = llvmlite.build_bitcast(
|
||
builder, adj_th2, anc_ptr_ty_th2)
|
||
else:
|
||
# 定义类 struct 大小不可得(opaque/未加载):fail-fast
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
cl,
|
||
f"this-adjust 兄弟 Mixin 定义类大小未知: 方法'{method_name}'"
|
||
f"定义类'{mc_anc}'的 struct 大小计算失败",
|
||
"InternalCompilerError")
|
||
elif is_first_parent_th == 0:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
cl,
|
||
f"this-adjust 字段查找失败: 方法'{method_name}'定义类'{mc_anc}'"
|
||
f"首字段'{anc_first_name_th}'在类'{class_name}'/'{mc_anc}'布局中未找到",
|
||
"InternalCompilerError")
|
||
elif is_first_parent_th == 0:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
cl,
|
||
f"this-adjust 子类结构体未注册: 方法'{method_name}'定义类'{mc_anc}',"
|
||
f"接收类'{class_name}'的 struct 未找到",
|
||
"InternalCompilerError")
|
||
else:
|
||
# 父类仅 __vtable__ 字段(无字段 CVTable 类):方法体不读
|
||
# 布局字段,无需调整(对齐 TPC:first_field_name None → ObjVal)
|
||
pass
|
||
elif anc_entry_th is not None and anc_entry_th.FieldCount == 0:
|
||
# 无字段父类:this 无需字节调整(见上方注释)
|
||
pass
|
||
elif is_first_parent_th == 0:
|
||
# 父类 struct 未注册:fail-fast,绝不静默用未调整的 obj_ptr
|
||
# 当 self(否则方法按自身布局读字段读到垃圾)
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
cl,
|
||
f"this-adjust 父类结构体未注册: 方法'{method_name}'定义类'{mc_anc}'的 struct 未找到",
|
||
"InternalCompilerError")
|
||
# self 参数按声明首参类型 coerce:跨模块 declare self 是类指针
|
||
# (%"sha1.Class"*,见 VpiReader._inject_method_declare),而对象指针
|
||
# 可能是 i8*(X|t.CPtr 联合简化)或 this-adjust 后的祖先指针,需
|
||
# bitcast 匹配声明签名(对齐 _call_method_on_ptr 的 coerce 块),
|
||
# 否则 llc 报 call 参数类型与 declare 不一致。
|
||
if found_func is not None:
|
||
pp_self: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
if pp_self is not None:
|
||
pty_self: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp_self)
|
||
if pty_self is not None:
|
||
cself_tm: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, self_arg, pty_self, None)
|
||
if cself_tm is not None:
|
||
self_arg = cself_tm
|
||
# 构建参数链表: self → arg1 → arg2 → ...
|
||
llvmlite.value_set_next(self_arg, None)
|
||
head: llvmlite.Value | t.CPtr = self_arg
|
||
tail: llvmlite.Value | t.CPtr = self_arg
|
||
arg_count_eff: int = 0
|
||
|
||
if kwc > 0 and found_func is not None:
|
||
# 关键字参数:遍历函数定义参数(跳过 self),位置参数优先,其余按名匹配
|
||
# 缺失参数用零值兜底,保持 call 参数数量与 define 一致
|
||
cur_param_k: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
if cur_param_k is not None:
|
||
cur_param_k = llvmlite.param_get_next(cur_param_k) # 跳过 self
|
||
pi_k: int = 0
|
||
while cur_param_k is not None:
|
||
arg_node_k: ast.AST | t.CPtr = None
|
||
if pi_k < can:
|
||
arg_node_k = cargs.get(pi_k)
|
||
else:
|
||
pname_k: str = llvmlite.param_get_name(cur_param_k)
|
||
if pname_k is not None:
|
||
ki_k: int
|
||
for ki_k in range(kwc):
|
||
kw_k: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(kw_calls.get(ki_k))
|
||
if kw_k is None or kw_k.arg is None or kw_k.value is None:
|
||
continue
|
||
if self._kwarg_name_matches(kw_k.arg, pname_k) == 1:
|
||
arg_node_k = kw_k.value
|
||
break
|
||
arg_val_k: llvmlite.Value | t.CPtr = None
|
||
if arg_node_k is not None:
|
||
# 先取形参类型(char 字面量 → str 形参需物化字符串,见 translate_constant)
|
||
pty_k0: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k)
|
||
arg_val_k = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg_node_k, None, 0, trans, pty_k0)
|
||
if arg_val_k is None:
|
||
# 缺失参数:零值兜底(保持参数数量匹配)。
|
||
# kw 省略的形参可能有默认值(查不到默认表 ≠ 无默认值),
|
||
# 零值兜底与原逻辑一致,禁止 fail-fast 误杀。
|
||
pty_k: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k)
|
||
if pty_k is not None:
|
||
arg_val_k = llvmlite.ConstZero(pool, pty_k)
|
||
if arg_val_k is not None:
|
||
pty_k2: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k)
|
||
if pty_k2 is not None:
|
||
arg_val_k = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, arg_val_k, pty_k2, arg_node_k)
|
||
llvmlite.value_set_next(arg_val_k, None)
|
||
llvmlite.value_set_next(tail, arg_val_k)
|
||
tail = arg_val_k
|
||
arg_count_eff += 1
|
||
pi_k += 1
|
||
cur_param_k = llvmlite.param_get_next(cur_param_k)
|
||
else:
|
||
# 位置参数(原逻辑)
|
||
for ai in range(can):
|
||
arg_node: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg_node is None:
|
||
continue
|
||
# 先取形参类型:单引号单字符字面量(CONST_CHAR)传给 str/指针
|
||
# 形参时需物化 1 字符字符串(translate_constant 依据 target_ty 判定),
|
||
# 否则 coerce inttoptr 把字符值当指针 → strlen 访问低地址崩溃。
|
||
pp: llvmlite.Param | t.CPtr = None
|
||
pty: llvmlite.LLVMType | t.CPtr = None
|
||
if found_func is not None:
|
||
pp = llvmlite.function_get_param_head(found_func)
|
||
pi: int = 0
|
||
while pp is not None and pi < ai + 1:
|
||
if pi == ai + 1:
|
||
break
|
||
pp = llvmlite.param_get_next(pp)
|
||
pi += 1
|
||
if pp is not None:
|
||
pty = llvmlite.param_get_ty(pp)
|
||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg_node, None, 0, trans, pty)
|
||
if arg_val is None:
|
||
continue
|
||
# 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1)
|
||
# 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: t.CSizeT)
|
||
# 未提升导致 call(i32) 与 define(i64) 不匹配,运行时读到垃圾高 32 位崩溃
|
||
if found_func is not None:
|
||
if pty is not None:
|
||
arg_val = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, arg_val, pty, arg_node)
|
||
else:
|
||
# found_func=None(跨模块 stub 未注入):数组实参按 C 语义
|
||
# 衰减为元素指针(对齐 TPC _decay_array_to_ptr)。否则
|
||
# _ensure_method_declare 用 [N x ty]* 实参类型建 declare,
|
||
# 与定义侧元素指针(如 md5.final 的 i8*)类型不匹配。
|
||
if arg_val.Ty is not None and self.Gen.ExprGenBase.is_ptr_type(arg_val.Ty) != 0:
|
||
arr_pointee_ma: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee
|
||
if arr_pointee_ma is not None:
|
||
match arr_pointee_ma:
|
||
case llvmlite.LLVMType.Array(arr_et_ma, _):
|
||
decayed_ma: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||
builder, arr_pointee_ma, arr_et_ma, arg_val,
|
||
llvmlite.const_int32(pool, 0))
|
||
if decayed_ma is not None:
|
||
arg_val = decayed_ma
|
||
case _:
|
||
pass
|
||
llvmlite.value_set_next(arg_val, None)
|
||
llvmlite.value_set_next(tail, arg_val)
|
||
tail = arg_val
|
||
arg_count_eff += 1
|
||
|
||
total_count: int = 1 + arg_count_eff
|
||
|
||
# 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数
|
||
# 查找函数的 defaults 信息
|
||
mdf_defaults: t.CVoid | t.CPtr = None
|
||
mdf_default_count: int = 0
|
||
mdf_param_count: int = 0
|
||
if trans is not None and trans._funcs is not None:
|
||
mdf_entry: GenTypes.FuncEntry | t.CPtr = ExprCallTable.find_func_entry_in_table(
|
||
trans._funcs, trans._func_count, lookup_name)
|
||
if mdf_entry is not None:
|
||
mdf_defaults = mdf_entry.Defaults
|
||
mdf_default_count = mdf_entry.DefaultCount
|
||
mdf_param_count = mdf_entry.ParamCount
|
||
# 全局默认参数表查询无条件执行:mdf_entry 命中时(泛型特化方法注册进
|
||
# 调用方函数表)Defaults 非 None 会短路跳过,但下方"用快照重建默认值"
|
||
# 分支依赖 mdf_gd(唯一持有 stdlib 常量快照处)——缺它必 fatal_error
|
||
# (ListTest list[int].__new__ 根因)
|
||
mdf_gd: GenTypes.FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(lookup_name)
|
||
if mdf_defaults is None and mdf_gd is not None:
|
||
mdf_defaults = mdf_gd.Defaults
|
||
mdf_default_count = mdf_gd.DefaultCount
|
||
mdf_param_count = mdf_gd.ParamCount
|
||
|
||
# 跨模块 stub 未注入兜底:如 self.Gen.ExprGenCdef.method 经 Generator
|
||
# 属性访问调用依赖模块方法,依赖收集不加载其 vpi → 函数表无
|
||
# ParamCount/默认参数 → 调用点缺参 → 被调函数读栈残留
|
||
# (IterTest 跨模块 CDefine 查找 depth=160 假递归根因)。用 vpi
|
||
# 文本缓存补全参数数,下方默认参数填充(含零值兜底)随即生效,
|
||
# declare/call 与 define 参数数对齐。
|
||
vpi_pa: str = None
|
||
if mdf_param_count == 0 and found_func is None:
|
||
vpi_sha1_p: str = None
|
||
if mc_entry is not None and mc_entry.ModuleSha1 is not None:
|
||
vpi_sha1_p = mc_entry.ModuleSha1
|
||
else:
|
||
vpi_sha1_p = self.Gen.StructGen.get_struct_sha1(class_name)
|
||
if vpi_sha1_p is not None:
|
||
vpi_pa = self.Gen.CallGenBase._vpi_method_param_annot(
|
||
pool, vpi_sha1_p, class_name, method_name)
|
||
if vpi_pa is not None and vpi_pa[0] != '\0':
|
||
vpi_pc2: int = 1
|
||
vi2: t.CSizeT = 0
|
||
while vpi_pa[vi2] != '\0':
|
||
if vpi_pa[vi2] == '@':
|
||
vpi_pc2 += 1
|
||
vi2 += 1
|
||
mdf_param_count = vpi_pc2 - 1 # 非 self 参数数
|
||
|
||
# [修复 2026-08-25] found_func 参数数回退:函数表/默认表无 ParamCount
|
||
# (mdf_param_count==0)但 found_func(模块内 declare)已找到时,用其
|
||
# 参数数作补全基准。缺它:省略默认参数(如 translate_value 的
|
||
# target_ty=None)的调用补全不触发 → call 实参(8) < define 形参(9)
|
||
# → x64 ABI 第 9 参读栈残留垃圾 → is_ptr_type(0x40) 崩溃(SlotsBugTest
|
||
# 二代编 translate_assign/AugAssign 崩溃根因)。
|
||
# 排除 EH 输出参数(%__eh_msg_out__/%__eh_code_out__):含 raise 方法
|
||
# 定义尾部注入 2 个 EH 形参,计入会让补全先补 zeroinitializer 占位,
|
||
# _emit_eh_guarded_call 再追加真实 EH 实参 → 双重注入(TestFBProject
|
||
# raise_disk() 崩溃同源,与 _call_method_on_ptr/CallGenMixin 一致)。
|
||
if mdf_param_count == 0 and found_func is not None:
|
||
ppcnt_f: int = 0
|
||
ppn_f: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
while ppn_f is not None:
|
||
fp_nm_f: str = llvmlite.param_get_name(ppn_f)
|
||
if fp_nm_f is None or (string.strcmp(fp_nm_f, "%__eh_msg_out__") != 0
|
||
and string.strcmp(fp_nm_f, "%__eh_code_out__") != 0):
|
||
ppcnt_f += 1
|
||
ppn_f = llvmlite.param_get_next(ppn_f)
|
||
if ppcnt_f > 1:
|
||
mdf_param_count = ppcnt_f - 1 # 非 self 非 EH 参数数
|
||
|
||
# 计算需要填充的参数(不含 self)
|
||
# arg_count_eff = 已提供的非 self 参数数量(含关键字模式完整构建)
|
||
# mdf_param_count = 函数定义的非 self 参数数量
|
||
if mdf_param_count > arg_count_eff:
|
||
mdf_offset: int = mdf_param_count - mdf_default_count
|
||
mdf_pi: int = arg_count_eff
|
||
while mdf_pi < mdf_param_count:
|
||
# 优先用默认值
|
||
if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset:
|
||
mdf_di: int = mdf_pi - mdf_offset
|
||
if mdf_di < mdf_default_count:
|
||
# 用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收,
|
||
# 直接回退读 AST 会 use-after-free——快照失败时 fail-fast 暴露,绝不读悬空 AST)
|
||
mdf_val: llvmlite.Value | t.CPtr = None
|
||
if mdf_gd is not None:
|
||
mdf_val = self.Gen.CallGenLeafKit._build_const_from_snapshot(
|
||
pool, mod, mdf_gd, mdf_di, trans, builder)
|
||
if mdf_val is None:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
cl,
|
||
f"跨模块默认参数无法重建(快照缺失,默认值需为简单常量): {lookup_name}",
|
||
"TypeError")
|
||
continue
|
||
llvmlite.value_set_next(mdf_val, None)
|
||
llvmlite.value_set_next(tail, mdf_val)
|
||
tail = mdf_val
|
||
total_count += 1
|
||
mdf_pi += 1
|
||
continue
|
||
# 无默认值时用零值兜底(需要 found_func 获取参数类型)。
|
||
# 默认参数表按裸名注册(如 "__init__"),跨模块 "ClassName.method"
|
||
# 查找常查不到——查不到 ≠ 无默认值(如 Buf.__init__(data, capacity)
|
||
# 缺的 length=0/owned=False 恰为零值),零值兜底语义一致。
|
||
if found_func is not None:
|
||
param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
skip_z: int = 0
|
||
while skip_z <= mdf_pi and param_node_z is not None:
|
||
param_node_z = llvmlite.param_get_next(param_node_z)
|
||
skip_z += 1
|
||
if param_node_z is not None:
|
||
zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z)
|
||
zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty)
|
||
if zero_val is not None:
|
||
llvmlite.value_set_next(zero_val, None)
|
||
llvmlite.value_set_next(tail, zero_val)
|
||
tail = zero_val
|
||
total_count += 1
|
||
elif vpi_pa is not None:
|
||
# found_func 为 None(stub 未注入):用 vpi 参数注解解析
|
||
# 缺失参数类型(段索引 mdf_pi+1,跳过首参 self 空段),
|
||
# 值取类型零值(默认参数值恰为零值;查不到 ≠ 无默认值)。
|
||
seg_idx_v: int = mdf_pi + 1
|
||
seg_no_v: int = 0
|
||
seg_cur_v: t.CSizeT = 0
|
||
while seg_no_v < seg_idx_v and vpi_pa[seg_cur_v] != '\0':
|
||
if vpi_pa[seg_cur_v] == '@':
|
||
seg_no_v += 1
|
||
seg_cur_v += 1
|
||
seg_start_v: t.CSizeT = seg_cur_v
|
||
seg_len_v: t.CSizeT = 0
|
||
while vpi_pa[seg_start_v + seg_len_v] != '\0' \
|
||
and vpi_pa[seg_start_v + seg_len_v] != '@':
|
||
seg_len_v += 1
|
||
if seg_no_v == seg_idx_v:
|
||
pty_v: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
|
||
if seg_len_v > 0:
|
||
seg_buf_v: bytes = stdlib.malloc(seg_len_v + 1)
|
||
if seg_buf_v is not None:
|
||
string.strncpy(seg_buf_v, vpi_pa + seg_start_v, seg_len_v)
|
||
seg_buf_v[seg_len_v] = '\0'
|
||
rty_v: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenBase._vpi_resolve_param_annot_ty(
|
||
pool, seg_buf_v)
|
||
if rty_v is not None:
|
||
pty_v = rty_v
|
||
stdlib.free(seg_buf_v)
|
||
zero_val_v: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, pty_v)
|
||
if zero_val_v is not None:
|
||
llvmlite.value_set_next(zero_val_v, None)
|
||
llvmlite.value_set_next(tail, zero_val_v)
|
||
tail = zero_val_v
|
||
total_count += 1
|
||
mdf_pi += 1
|
||
|
||
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用
|
||
# (不依赖 found_func — 继承的虚方法可能没有子类实现)
|
||
# 复用前面已获取的 mc_entry(find_struct_by_type 规避跨模块同名找错)
|
||
mc_has_vt: int = 0
|
||
mc_method_idx: int = -1
|
||
if mc_entry is not None:
|
||
mc_has_vt = mc_entry.HasVTable
|
||
if mc_has_vt == 1 and mc_entry.VTableMethods is not None:
|
||
mc_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(mc_entry.VTableMethods, t.CPtr))
|
||
for mc_mi in range(mc_entry.VTableMethodCount):
|
||
mc_mname_addr: t.CSizeT = mc_methods_arr[mc_mi]
|
||
if mc_mname_addr == 0:
|
||
continue
|
||
mc_mname: str = (str | t.CPtr)(t.CVoid(mc_mname_addr, t.CPtr))
|
||
if mc_mname is not None and string.strcmp(mc_mname, method_name) == 0:
|
||
mc_method_idx = mc_mi
|
||
break
|
||
if mc_has_vt == 1 and mc_method_idx >= 0:
|
||
# 虚分派 self 必须用调整后的 self_arg(多继承 this 调整),
|
||
# 否则 B.get_b 收到未调整的 AB*,方法体内按 B 布局读字段错位。
|
||
# vtable 读取必须用对象头 obj_ptr(调整后 self 头部是父类字段值)。
|
||
return self._do_virtual_call(pool, builder, mod, class_name, method_name,
|
||
self_arg, head, total_count, found_func, call_ret_ty,
|
||
obj_ptr)
|
||
|
||
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
|
||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count)
|
||
# 检查变长函数 + C ABI 提升(cargs 是实参 AST,self_offset=1 跳过 self)
|
||
is_variadic_3441: int = self.Gen.CallGenVa._check_and_promote_variadic_call(
|
||
pool, builder, mod, call_name, head, total_count, cargs, 1, trans)
|
||
# try-except:方法含 raise(EH 输出参数)时追加输出实参 + 调用后检测
|
||
# [MMDBG] 诊断:调用发射前状态(用后移除)
|
||
if string.strcmp(method_name, "Sub") == 0:
|
||
stdio.printf("[MMDBG] pre-call call_name=%s ret_ty_ptr=%llu head=%llu count=%d\n",
|
||
call_name, t.CUInt64T(call_ret_ty), t.CUInt64T(head), total_count)
|
||
res_final: llvmlite.Value | t.CPtr = self.Gen.CallGenLeafKit._emit_eh_guarded_call(
|
||
builder, pool, mod, trans, found_func, call_name, head, total_count,
|
||
call_ret_ty, is_variadic_3441)
|
||
# [MMDBG] 诊断:调用发射结果(用后移除)
|
||
if string.strcmp(method_name, "Sub") == 0:
|
||
if res_final is not None:
|
||
stdio.printf("[MMDBG] _emit_eh_guarded_call ok\n")
|
||
else:
|
||
stdio.printf("[MMDBG] _emit_eh_guarded_call None\n")
|
||
return res_final
|
||
# ============================================================
|
||
# _translate_super_call — super().method(args) → 静态调用父类方法
|
||
#
|
||
# Python super 语义(2026-08-10 实现):
|
||
# - 当前类来自 self.CurClassName(_translate_method 翻译方法体时设置)
|
||
# - 父类查找:沿 get_mro_chain(CurClassName) 跳过自身,找第一个定义 method 的祖先
|
||
# - self 指针:符号表 self 变量 alloca load(对象头,复用 c.Addr(self) 模式)
|
||
# - this_adjust:父类字段区在子类中字节偏移 delta>0 时 GEP i8* + delta
|
||
# (复用 _field_byte_offset 字节偏移法,与 _translate_method_call 一致)
|
||
# - 静态调用父类实现:不虚分派(super() 不触发子类 override)
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _translate_super_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
cl: ast.Call | t.CPtr,
|
||
method_name: str,
|
||
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
|
||
"""super().method(args) → 父类方法静态调用,返回 call 结果 Value"""
|
||
if pool is None or builder is None or cl is None or method_name is None:
|
||
return None
|
||
if trans is None:
|
||
return None
|
||
# 1. 当前方法所属类:从 self 变量的注解类名获取(_translate_method
|
||
# 注册 self 时 set_var_annot_class_name(SymTab, "self", class_name))。
|
||
# 不用 Mixin 字段:TPV Mixin 字段按声明类独立布局(Generator 多继承
|
||
# 去重只保留首个声明),ClassGenMixin 写的 CurClassName 与 CallGenMixin
|
||
# 读的位置偏移不一致 → 运行时读到空 → super() 误报"只能在类方法内使用"。
|
||
self_entry: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||
trans.SymTab, "self")
|
||
if self_entry is None:
|
||
self_entry = self.Gen.VarGen.lookup_var_entry(trans.SymTab, "cls")
|
||
if self_entry is None:
|
||
self.Gen.TypeGenErr.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError")
|
||
return None
|
||
cur_class: str = self_entry.AnnotClassName
|
||
if cur_class is None:
|
||
self.Gen.TypeGenErr.fatal_error(cl, "super() 只能在类方法内使用(self 无注解类名)")
|
||
return None
|
||
# 2. 沿 MRO 跳过自身,找第一个定义 method 的祖先类
|
||
anc: str = None
|
||
mro_sp: t.CSizeT | t.CPtr = self.Gen.StructGen.get_mro_chain(pool, cur_class)
|
||
mi_sp: int = 1
|
||
while mro_sp is not None and mro_sp[mi_sp] != 0:
|
||
anc_sp: str = (str | t.CPtr)(t.CVoid(mro_sp[mi_sp], t.CPtr))
|
||
if anc_sp is not None:
|
||
probe_sp: str = pool.alloc(160)
|
||
if probe_sp is not None:
|
||
viperlib.snprintf(probe_sp, 160, "%s.%s", anc_sp, method_name)
|
||
if self.Gen.CallGenLeafKit.find_func_global(probe_sp) is not None:
|
||
anc = anc_sp
|
||
break
|
||
mi_sp += 1
|
||
if anc is None:
|
||
err_sp: str = pool.alloc(256)
|
||
if err_sp is not None:
|
||
viperlib.snprintf(err_sp, 256, "super(): 当前类 %s 的父类链未定义方法 %s",
|
||
cur_class, method_name)
|
||
self.Gen.TypeGenErr.fatal_error(cl, err_sp, "TypeError")
|
||
self.Gen.TypeGenErr.fatal_error(cl, "super(): 父类链未定义方法", "TypeError")
|
||
return None
|
||
# 3. self 指针(self 变量 alloca load,复用 c.Addr(self) 模式)
|
||
if self_entry.Alloca is None or self_entry.Alloca.Ty is None:
|
||
self.Gen.TypeGenErr.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError")
|
||
return None
|
||
self_ptr: llvmlite.Value | t.CPtr = None
|
||
match self_entry.Alloca.Ty:
|
||
case llvmlite.LLVMType.Ptr(inner1):
|
||
match inner1:
|
||
case llvmlite.LLVMType.Ptr(inner2):
|
||
obj_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, inner2)
|
||
self_ptr = llvmlite.build_load(builder, obj_ty_sp, self_entry.Alloca)
|
||
case _:
|
||
self_ptr = llvmlite.build_load(builder, self_entry.Alloca.Ty, self_entry.Alloca)
|
||
case _:
|
||
self_ptr = self_entry.Alloca
|
||
if self_ptr is None:
|
||
return None
|
||
# 3. this_adjust(字节偏移法:父类字段区在子类中的偏移差)
|
||
self_arg: llvmlite.Value | t.CPtr = self_ptr
|
||
if string.strcmp(anc, cur_class) != 0:
|
||
anc_entry_sp: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(anc)
|
||
if anc_entry_sp is not None and anc_entry_sp.FieldCount > 0:
|
||
first_name_sp: str = None
|
||
afi_sp: int = 0
|
||
while afi_sp < anc_entry_sp.FieldCount:
|
||
afe_sp: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry(
|
||
anc_entry_sp, afi_sp)
|
||
if afe_sp is not None:
|
||
afn_sp: str = self.Gen.StructGen.get_field_name_ptr(afe_sp)
|
||
if afn_sp is not None and string.strcmp(afn_sp, "__vtable__") != 0:
|
||
first_name_sp = afn_sp
|
||
break
|
||
afi_sp += 1
|
||
if first_name_sp is not None:
|
||
sub_entry_sp: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct(
|
||
cur_class)
|
||
if sub_entry_sp is not None:
|
||
anc_field_sp: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field(
|
||
anc_entry_sp.Ty, first_name_sp)
|
||
sub_field_sp: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen.lookup_field(
|
||
sub_entry_sp.Ty, first_name_sp)
|
||
if anc_field_sp is not None and sub_field_sp is not None:
|
||
anc_off_sp: int = self._field_byte_offset(
|
||
pool, anc_entry_sp, anc_field_sp.Index)
|
||
sub_off_sp: int = self._field_byte_offset(
|
||
pool, sub_entry_sp, sub_field_sp.Index)
|
||
delta_sp: int = sub_off_sp - anc_off_sp
|
||
if delta_sp > 0:
|
||
i8_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
|
||
i8_ptr_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_sp)
|
||
obj_i8_sp: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
|
||
builder, self_ptr, i8_ptr_sp)
|
||
dval_sp: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, delta_sp)
|
||
adj_sp: llvmlite.Value | t.CPtr = llvmlite.build_gep(
|
||
builder, i8_ty_sp, obj_i8_sp, dval_sp)
|
||
if adj_sp is not None:
|
||
anc_ptr_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, anc_entry_sp.Ty)
|
||
# 同上:跨模块祖先类型 bitcast 前确保 opaque 声明,
|
||
# 否则 llc 报 "use of undefined type"
|
||
llvmlite.module_ensure_opaque_for_type(mod, pool, anc_ptr_sp)
|
||
self_arg = llvmlite.build_bitcast(builder, adj_sp, anc_ptr_sp)
|
||
# 4. 查找父类方法函数 + 构造调用名(SHA1 mangled)
|
||
anc_lookup: str = pool.alloc(160)
|
||
if anc_lookup is None:
|
||
return None
|
||
viperlib.snprintf(anc_lookup, 160, "%s.%s", anc, method_name)
|
||
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, anc_lookup)
|
||
call_name: str = anc_lookup
|
||
anc_sha1_sp: str = self.Gen.StructGen.get_struct_sha1(anc)
|
||
if anc_sha1_sp is None:
|
||
anc_sha1_sp = trans.ModuleSha1
|
||
if found_func is not None:
|
||
fname_sp: str = llvmlite.function_get_name(found_func)
|
||
if fname_sp is not None:
|
||
call_name = fname_sp
|
||
else:
|
||
if anc_sha1_sp is not None:
|
||
mangled_sp: str = self.Gen.FuncGenBase._mangle_name_with_sha1(anc_sha1_sp, anc_lookup)
|
||
if mangled_sp is not None:
|
||
call_name = mangled_sp
|
||
# 5. 翻译参数 + 按形参 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1)
|
||
cargs_sp: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
can_sp: t.CSizeT = 0
|
||
if cargs_sp is not None:
|
||
can_sp = len(cargs_sp)
|
||
llvmlite.value_set_next(self_arg, None)
|
||
head: llvmlite.Value | t.CPtr = self_arg
|
||
tail: llvmlite.Value | t.CPtr = self_arg
|
||
arg_count_sp: int = 1
|
||
for ai_sp in range(can_sp):
|
||
arg_node_sp: ast.AST | t.CPtr = cargs_sp.get(ai_sp)
|
||
if arg_node_sp is None:
|
||
continue
|
||
# 先取形参类型(char 字面量 → str 形参需物化字符串,见 translate_constant)
|
||
pp_sp: llvmlite.Param | t.CPtr = None
|
||
pty_sp: llvmlite.LLVMType | t.CPtr = None
|
||
if found_func is not None:
|
||
pp_sp = llvmlite.function_get_param_head(found_func)
|
||
pi_sp: int = 0
|
||
while pp_sp is not None and pi_sp < ai_sp + 1:
|
||
if pi_sp == ai_sp + 1:
|
||
break
|
||
pp_sp = llvmlite.param_get_next(pp_sp)
|
||
pi_sp += 1
|
||
if pp_sp is not None:
|
||
pty_sp = llvmlite.param_get_ty(pp_sp)
|
||
arg_val_sp: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg_node_sp, None, 0, trans, pty_sp)
|
||
if arg_val_sp is None:
|
||
continue
|
||
if pty_sp is not None:
|
||
arg_val_sp = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, arg_val_sp, pty_sp, arg_node_sp)
|
||
else:
|
||
# found_func=None:数组实参按 C 语义衰减为元素指针
|
||
# (与 _translate_method_call 一致,避免 declare 类型不匹配)
|
||
if arg_val_sp.Ty is not None and self.Gen.ExprGenBase.is_ptr_type(arg_val_sp.Ty) != 0:
|
||
arr_pointee_sp: llvmlite.LLVMType | t.CPtr = arg_val_sp.Ty.Pointee
|
||
if arr_pointee_sp is not None:
|
||
match arr_pointee_sp:
|
||
case llvmlite.LLVMType.Array(arr_et_sp, _):
|
||
decayed_sp: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||
builder, arr_pointee_sp, arr_et_sp, arg_val_sp,
|
||
llvmlite.const_int32(pool, 0))
|
||
if decayed_sp is not None:
|
||
arg_val_sp = decayed_sp
|
||
case _:
|
||
pass
|
||
llvmlite.value_set_next(arg_val_sp, None)
|
||
llvmlite.value_set_next(tail, arg_val_sp)
|
||
tail = arg_val_sp
|
||
arg_count_sp += 1
|
||
# 6. 返回类型:found_func → 特殊方法 → text.ll/vpi
|
||
ret_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
if found_func is not None:
|
||
frt_sp: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
|
||
if frt_sp is not None:
|
||
ret_ty_sp = frt_sp
|
||
else:
|
||
sp_ty_sp: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, anc, method_name)
|
||
if sp_ty_sp is not None:
|
||
ret_ty_sp = sp_ty_sp
|
||
else:
|
||
looked_sp: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
|
||
pool, anc_sha1_sp, anc, method_name)
|
||
if looked_sp is not None:
|
||
ret_ty_sp = looked_sp
|
||
else:
|
||
vpi_ret_sp: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
|
||
pool, anc_sha1_sp, anc, method_name)
|
||
if vpi_ret_sp is not None:
|
||
ret_ty_sp = vpi_ret_sp
|
||
else:
|
||
# 查找链(函数/text.ll/vpi stub)全部未命中:fail-fast,
|
||
# 绝不静默保持默认 i32(会截断指针/i64 返回值)
|
||
# Phase A 依赖未就绪(anc_sha1_sp None / 定义模块 text.ll
|
||
# 未生成):标记 pending 下遍重译(对齐 L4783-4790),
|
||
# 绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。
|
||
if anc_sha1_sp is None \
|
||
or self._dep_text_ll_exists(pool, anc_sha1_sp) == 0:
|
||
if trans is not None:
|
||
trans._deps_pending = 1
|
||
# [DEPDBG] 临时诊断:特殊方法依赖未就绪即 pending 的根因(用后移除)
|
||
dbg_ms4: str = trans.ModuleSha1 if (trans is not None and trans.ModuleSha1 is not None) else "?"
|
||
stdio.printf("[DEPDBG] pending(special_ret): mod=%s cls=%s method=%s sha1=%s\n",
|
||
dbg_ms4, anc if anc is not None else "?",
|
||
method_name,
|
||
anc_sha1_sp if anc_sha1_sp is not None else "none")
|
||
# 依赖未就绪:保持默认 i32(build_call(Void) 返回 None
|
||
# 会破坏表达式翻译;pending 文件本遍不写盘,下遍重译)
|
||
ret_ty_sp = llvmlite.Int32(pool)
|
||
else:
|
||
self._fail_method_ret_ty(method_name, cl)
|
||
# 7. 跨模块:创建 declare;生成 call
|
||
if found_func is None:
|
||
self._ensure_method_declare(pool, mod, call_name, ret_ty_sp, head, arg_count_sp)
|
||
is_variadic_sp: int = self.Gen.CallGenVa._check_and_promote_variadic_call(
|
||
pool, builder, mod, call_name, head, arg_count_sp, cargs_sp, 1, trans)
|
||
return llvmlite.build_call(builder, call_name, head, arg_count_sp, ret_ty_sp, is_variadic_sp)
|
||
# ============================================================
|
||
# _field_byte_offset — 计算字段在结构体布局中的字节偏移
|
||
#
|
||
# 按 LLVM 布局遍历 struct elements 带对齐累加(与 ClassGenMixin._get_type_size
|
||
# 的 padding 规则一致)。field_index 是 FieldEntry.Index(OOP 类 __vtable__ 占 0)。
|
||
# 供多继承 this 调整(字节偏移法)计算 delta。
|
||
# ============================================================
|
||
|
||
# ============================================================
|
||
def _field_byte_offset(self, pool: memhub.MemBuddy | t.CPtr,
|
||
entry: GenTypes.StructEntry | t.CPtr,
|
||
field_index: int) -> int:
|
||
"""计算字段在结构体中的字节偏移(含对齐 padding),无法计算返回 0"""
|
||
if pool is None or entry is None or entry.Ty is None or field_index < 0:
|
||
return 0
|
||
match entry.Ty:
|
||
case llvmlite.LLVMType.Struct(fields, fcount, name):
|
||
offset_fb: int = 0
|
||
cur_fb: llvmlite.ParamNode | t.CPtr = fields
|
||
i_fb: int = 0
|
||
while cur_fb is not None and i_fb < field_index:
|
||
if cur_fb.Ty is not None:
|
||
fty_fb: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur_fb.Ty)
|
||
fsize_fb: int = self.Gen.ClassGenEnum._get_type_size(fty_fb)
|
||
falign_fb: int = self.Gen.ClassGenEnum._get_type_align(fty_fb)
|
||
if falign_fb > 1:
|
||
rem_fb: int = offset_fb % falign_fb
|
||
if rem_fb != 0:
|
||
offset_fb += falign_fb - rem_fb
|
||
offset_fb += fsize_fb
|
||
cur_fb = cur_fb.Next
|
||
i_fb += 1
|
||
# 字段自身对齐
|
||
if cur_fb is not None and cur_fb.Ty is not None:
|
||
fty2_fb: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur_fb.Ty)
|
||
falign2_fb: int = self.Gen.ClassGenEnum._get_type_align(fty2_fb)
|
||
if falign2_fb > 1:
|
||
rem2_fb: int = offset_fb % falign2_fb
|
||
if rem2_fb != 0:
|
||
offset_fb += falign2_fb - rem2_fb
|
||
return offset_fb
|
||
case _:
|
||
return 0
|
||
# ============================================================
|
||
# _kwarg_name_matches — 检查关键字参数名是否匹配函数参数名
|
||
#
|
||
# 函数参数名在 LLVM IR 中带 % 前缀(如 "%a"),关键字参数名无前缀(如 "a")
|
||
# 跳过 % 前缀后逐字符比较
|
||
# ============================================================
|
||
def _kwarg_name_matches(self, kw_arg: str,
|
||
param_name: str) -> int:
|
||
"""检查关键字参数名 kw_arg 是否匹配参数名 param_name(跳过 % 前缀)"""
|
||
if kw_arg is None or param_name is None:
|
||
return 0
|
||
start: t.CSizeT = 0
|
||
if param_name[0] == '%':
|
||
start = 1
|
||
for i, ch in enumerate(kw_arg):
|
||
c: t.CChar = param_name[start + i]
|
||
if c == '\0' or c != ch:
|
||
return 0
|
||
if param_name[start + i + 1] != '\0':
|
||
return 0
|
||
return 1 |