From 1718738a19b88166e4dda978390f0933d10641cb Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 17 Aug 2026 06:34:33 +0800 Subject: [PATCH] =?UTF-8?q?refactor(gen):=20CallGenMixin=20=E9=98=B6?= =?UTF-8?q?=E6=AE=B5=20B=20=E6=8B=86=E5=87=BA=206=20=E7=BB=84=EF=BC=88Ctor?= =?UTF-8?q?/Call/Prop/Fd/Vt/Va=EF=BC=89=EF=BC=8C=E9=A1=B6=E5=B1=82?= =?UTF-8?q?=E5=89=A9=20translate=5Fcall=20=E4=B8=AD=E6=9E=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/lib/core/Gen/CallGenCall.vp | 1499 +++++++++ App/lib/core/Gen/CallGenCtor.vp | 1049 ++++++ App/lib/core/Gen/CallGenFd.vp | 437 +++ App/lib/core/Gen/CallGenMixin.vp | 3856 +---------------------- App/lib/core/Gen/CallGenProp.vp | 455 +++ App/lib/core/Gen/CallGenVa.vp | 334 ++ App/lib/core/Gen/CallGenVt.vp | 251 ++ App/lib/core/Gen/Generator.vp | 9 + App/lib/core/Handles/HandlesExprCall.vp | 51 + 9 files changed, 4123 insertions(+), 3818 deletions(-) create mode 100644 App/lib/core/Gen/CallGenCall.vp create mode 100644 App/lib/core/Gen/CallGenCtor.vp create mode 100644 App/lib/core/Gen/CallGenFd.vp create mode 100644 App/lib/core/Gen/CallGenProp.vp create mode 100644 App/lib/core/Gen/CallGenVa.vp create mode 100644 App/lib/core/Gen/CallGenVt.vp diff --git a/App/lib/core/Gen/CallGenCall.vp b/App/lib/core/Gen/CallGenCall.vp new file mode 100644 index 0000000..acd328b --- /dev/null +++ b/App/lib/core/Gen/CallGenCall.vp @@ -0,0 +1,1499 @@ +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.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + +# ============================================================ +# 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 — 返回类型 + # ============================================================ + + # ============================================================ + # _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 找错) + vc_entry: HandlesStruct.StructEntry | t.CPtr = None + struct_ty: llvmlite.LLVMType | t.CPtr = None + if self_ptr.Ty is not None: + vc_entry = HandlesStruct.get_struct_type_from_value(self_ptr) + if vc_entry is not None: + # vc_entry 是 struct_ty(LLVMType),需要找 StructEntry + vc_entry = HandlesStruct.find_struct_by_type(vc_entry) + if vc_entry is not None: + struct_ty = vc_entry.Ty + if struct_ty is None: + struct_ty = HandlesStruct.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 = HandlesStruct.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 = HandlesStruct.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 指针为首个参数 + # 如果该方法在虚表中,则走虚方法分发路径(间接调用) + # ============================================================ + + # ============================================================ + # _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: HandlesStruct.StructEntry | t.CPtr = None + cmop_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(self_ptr) + if cmop_struct_ty is not None: + cmop_entry = HandlesStruct.find_struct_by_type(cmop_struct_ty) + if cmop_entry is None: + cmop_entry = HandlesStruct.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 = HandlesStruct.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) + HandlesType.fatal_error(node, err_msg) + HandlesType.fatal_error(node, "找不到模块 SHA1") + mangled_len2: t.CSizeT = string.strlen(cls_sha1) + string.strlen(lookup_name) + 2 + mangled2: str = pool.alloc(mangled_len2) + if mangled2 is not None: + viperlib.snprintf(mangled2, mangled_len2, "%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) + HandlesType.fatal_error(node, err_cm1) + HandlesType.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) + HandlesType.fatal_error(node, err_cm2) + HandlesType.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) + HandlesType.fatal_error(node, err_cm3) + HandlesType.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 未生成(方法定义模块尚未翻译)→ 标记重试, + # 保持 void 继续(对齐 _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 + call_ret_ty = llvmlite.Void(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) + HandlesType.fatal_error(node, err_cm4) + HandlesType.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: FuncEntry | t.CPtr = HandlesExprCall.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: FuncDefaultsEntry | t.CPtr = HandlesExprCall.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 + + # 计算需要填充的参数(不含 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 = HandlesExprCall._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__ 报错行号丢失根因) + HandlesType.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 + 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 = HandlesExpr.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) + + return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0) + # ============================================================ + # _translate_method_call - 翻译方法调用 obj.method(args) + # + # 生成: call @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...) + # + # obj_ptr 是对象变量的 alloca(Ptr(StructTy)),作为 self 参数传入 + # ============================================================ + + # ============================================================ + # _translate_method_call - 翻译方法调用 obj.method(args) + # + # 生成: call @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: HandlesStruct.StructEntry | t.CPtr = None + mc_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(obj_ptr) + if mc_struct_ty is not None: + mc_entry = HandlesStruct.find_struct_by_type(mc_struct_ty) + if mc_entry is None: + mc_entry = HandlesStruct.find_struct(class_name) + + # 构造方法查找名: 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) + + # 泛型模板类方法:特化函数名带类型参数({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 = HandlesStruct.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 + + # 确定调用名(默认 "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 = HandlesStruct.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 = HandlesStruct.get_struct_sha1(class_name) + if ret_anc_sha1 is None: + # 沿 MRO 找第一个有 SHA1 的类 + mro_s0: t.CSizeT | t.CPtr = HandlesStruct.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 = HandlesStruct.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 + spec_name_g: str = HandlesClassDef._specialize_generic_class( + trans, base_buf_g, ta_list_g) + if spec_name_g is not None: + # 特化后重新查找特化函数(特化名 = 调用点类名) + 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 + if gen_done == 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 = HandlesStruct.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 = HandlesStruct.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 = HandlesStruct.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 = HandlesStruct.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 未生成(方法定义模块尚未翻译)→ 标记 + # 重试,保持 void 继续(下遍依赖生成后可精确解析),对齐跨模块 + # 函数路径 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 + call_ret_ty = llvmlite.Void(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 = HandlesStruct.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 = HandlesStruct.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 + call_ret_ty = llvmlite.Void(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 难以定位) + HandlesType.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: + anc_entry_th: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(mc_anc) + 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: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( + anc_entry_th, afi_th) + if afe_th is not None: + afn_th: str = HandlesStruct.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: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( + class_name) + if sub_entry_th is not None: + anc_field_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( + anc_entry_th.Ty, anc_first_name_th) + sub_field_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.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) + self_arg = llvmlite.build_bitcast(builder, adj_th, anc_ptr_ty_th) + # 构建参数链表: 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: + arg_val_k = HandlesExpr.translate_value( + builder, pool, mod, arg_node_k, None, 0, trans) + 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 = HandlesExpr.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 + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + 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: + pp: llvmlite.Param | t.CPtr = 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.LLVMType | t.CPtr = llvmlite.param_get_ty(pp) + if pty is not None: + arg_val = HandlesExpr.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 HandlesExpr.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: FuncEntry | t.CPtr = HandlesExprCall.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: FuncDefaultsEntry | t.CPtr = HandlesExprCall.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 + + # 计算需要填充的参数(不含 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 = HandlesExprCall._build_const_from_snapshot( + pool, mod, mdf_gd, mdf_di, trans, builder) + if mdf_val is None: + HandlesType.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 + 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 = HandlesExprCall._check_and_promote_variadic_call( + pool, builder, mod, call_name, head, total_count, cargs, 1, trans) + # try-except:方法含 raise(EH 输出参数)时追加输出实参 + 调用后检测 + return HandlesExprCall._emit_eh_guarded_call( + builder, pool, mod, trans, found_func, call_name, head, total_count, + call_ret_ty, is_variadic_3441) + # ============================================================ + # _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) + # ============================================================ + + # ============================================================ + # _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: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, "self") + if self_entry is None: + self_entry = HandlesVar.lookup_var_entry(trans.SymTab, "cls") + if self_entry is None: + HandlesType.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError") + return None + cur_class: str = self_entry.AnnotClassName + if cur_class is None: + HandlesType.fatal_error(cl, "super() 只能在类方法内使用(self 无注解类名)") + return None + # 2. 沿 MRO 跳过自身,找第一个定义 method 的祖先类 + anc: str = None + mro_sp: t.CSizeT | t.CPtr = HandlesStruct.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 HandlesExprCall.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) + HandlesType.fatal_error(cl, err_sp, "TypeError") + HandlesType.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: + HandlesType.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: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.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: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( + anc_entry_sp, afi_sp) + if afe_sp is not None: + afn_sp: str = HandlesStruct.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: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( + cur_class) + if sub_entry_sp is not None: + anc_field_sp: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( + anc_entry_sp.Ty, first_name_sp) + sub_field_sp: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.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) + 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 = HandlesStruct.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 = HandlesFunctions._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 + arg_val_sp: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg_node_sp, None, 0, trans) + if arg_val_sp is None: + continue + if found_func is not None: + pp_sp: llvmlite.Param | t.CPtr = 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.LLVMType | t.CPtr = llvmlite.param_get_ty(pp_sp) + if pty_sp is not None: + arg_val_sp = HandlesExpr.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 HandlesExpr.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 + ret_ty_sp = llvmlite.Void(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 = HandlesExprCall._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。 + # ============================================================ + + # ============================================================ + # _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: HandlesStruct.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 = HandlesClassDef._get_type_size(fty_fb) + falign_fb: int = HandlesClassDef._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 = HandlesClassDef._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") + # 跳过 % 前缀后逐字符比较 + # ============================================================ + + # ============================================================ + # _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 \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenCtor.vp b/App/lib/core/Gen/CallGenCtor.vp new file mode 100644 index 0000000..45efca6 --- /dev/null +++ b/App/lib/core/Gen/CallGenCtor.vp @@ -0,0 +1,1049 @@ +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.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + +# ============================================================ +# CallGenCtor - CallGenMixin 拆分(阶段 B):结构体构造 / 枚举构造 / 泛型构造 / 类型转换 +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenCtor(CallGenBase.CallGenBase): + """结构体构造 / 枚举构造 / 泛型构造 / 类型转换""" + + # ============================================================ + # _apply_struct_defaults — 应用结构体字段的默认值 + # + # 在 zeroinitializer 之后、显式参数之前调用 + # 遍历所有字段,对有默认值的字段翻译并 store + # 显式参数(位置/关键字)后续会覆盖默认值 + # ============================================================ + def _apply_struct_defaults(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + tmp: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr): + """应用结构体字段的默认值""" + # 用类型指针定位 entry,规避跨模块同名 find_struct 找错 + entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + if entry is None: + # fast-fail: 结构体类型未注册,静默 return 会导致字段未初始化 + VLogger.error( + f"结构体类型未注册,无法应用默认值: {class_name}", + "HandlesExprCall") + return + for fi in range(entry.FieldCount): + fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( + entry, fi) + if fe is None: + # fast-fail: 字段索引越界(entry.FieldCount 与实际不一致) + VLogger.error( + f"字段索引越界,无法获取字段 entry: {class_name}", + "HandlesExprCall") + continue + if fe.DefaultVal is None: + continue # 合理跳过:无默认值的字段 + # 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store + # (与 _generate_before_init 一致;translate_value 会把列表字面量 + # 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。 + # Mixin 静态绑定:跨 Mixin 方法必须走 HandlesAnnAssign 模块级委托。 + if fe.Ty is not None and HandlesExpr.is_array_type(fe.Ty) != 0 \ + and fe.DefaultVal.kind() == ast.ASTKind.List: + field_ptr_arr2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr_arr2 is not None: + zero_arr2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, fe.Ty) + if zero_arr2 is not None: + llvmlite.build_store(builder, zero_arr2, field_ptr_arr2) + HandlesAnnAssign._init_global_array_from_list( + builder, pool, mod, field_ptr_arr2, fe.DefaultVal, trans) + continue + default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, fe.DefaultVal, None, 0, trans) + if default_val is None: + # fast-fail: 默认值翻译失败(如引用了未定义符号) + VLogger.error( + f"字段默认值翻译失败: {class_name}", + "HandlesExprCall") + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) + VLogger.error( + f"字段 GEP 失败,类型不匹配: {class_name}", + "HandlesExprCall") + continue + default_val = HandlesExpr.coerce_to_type(builder, default_val, fe.Ty, fe.DefaultVal) + llvmlite.build_store(builder, default_val, field_ptr) + # ============================================================ + # _translate_struct_ctor — 结构体构造函数 Point(10, 20) + # + # 生成: + # %tmp = alloca {i32, i32} + # store {i32, i32} zeroinitializer, {i32, i32}* %tmp + # %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0 + # store i32 10, i32* %f0 + # %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1 + # store i32 20, i32* %f1 + # %result = load {i32, i32}, {i32, i32}* %tmp + # ============================================================ + + # ============================================================ + # _translate_struct_ctor — 结构体构造函数 Point(10, 20) + # + # 生成: + # %tmp = alloca {i32, i32} + # store {i32, i32} zeroinitializer, {i32, i32}* %tmp + # %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0 + # store i32 10, i32* %f0 + # %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1 + # store i32 20, i32* %f1 + # %result = load {i32, i32}, {i32, i32}* %tmp + # ============================================================ + def _translate_struct_ctor(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """结构体构造函数:按字段顺序 store 参数值,返回结构体值 + + OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load + 普通结构体:alloca → zero + defaults → store 参数 → load + """ + # 创建临时 alloca + # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) + HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return llvmlite.ConstZero(pool, struct_ty) + # 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的 + # fatal_error 显示构造调用行号(本函数无 cl 参数,实参节点最接近调用点) + diag_node_ct: ast.AST | t.CPtr = None + if cargs is not None and len(cargs) > 0: + diag_node_ct = cargs.get(0) + + # 检查是否为 OOP 结构体(用类型指针定位 entry,规避跨模块同名 find_struct 找错) + ctor_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + is_oop: int = 0 + if ctor_entry is not None: + is_oop = ctor_entry.IsOOP + + # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) + # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) + # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) + if is_oop == 0 and class_name is not None: + init_lookup_name: str = pool.alloc(128) + if init_lookup_name is not None: + viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name) + # 方案1: 检查当前模块的函数声明 + init_found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, init_lookup_name) + if init_found_func is not None: + is_oop = 1 + if ctor_entry is not None: + ctor_entry.IsOOP = 1 + ctor_entry.HasInit = 1 + else: + # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) + init_defaults_entry: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(init_lookup_name) + if init_defaults_entry is not None: + is_oop = 1 + if ctor_entry is not None: + ctor_entry.IsOOP = 1 + ctor_entry.HasInit = 1 + + if is_oop != 0: + # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 + storage_ptr: llvmlite.Value | t.CPtr = tmp + + # 如果有 __new__,调用 __new__(tmp, args...) 获取实际存储指针 + # __new__ 签名与 __init__ 一样(self + args),返回 Ptr(struct_ty) + has_new_flag: int = 0 + if ctor_entry is not None: + has_new_flag = ctor_entry.HasNew + # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) + if has_new_flag != 0: + new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if new_arg_vals is not None: + string.memset(new_arg_vals, 0, 8 * 32) + new_arg_count: int = 0 + for nai in range(can): + new_arg_node: ast.AST | t.CPtr = cargs.get(nai) + if new_arg_node is None: + continue + new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, new_arg_node, None, 0, trans) + if new_av is not None: + if new_arg_count < 32: + new_arg_vals[new_arg_count] = t.CSizeT(new_av) + new_arg_count += 1 + + new_ptr: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( + pool, builder, mod, class_name, + "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct) + if new_ptr is not None: + storage_ptr = new_ptr + # __new__ 只保证返回"实例存储指针",声明类型通常是 + # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 + # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 + # obj.method(如 parser.add_argument)get_class_name_by_type + # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 + # bitcast 只改类型层视图,运行时零开销(指针位不变)。 + if new_ptr.Ty is not None: + nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): + nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) + if nw_bc is not None: + storage_ptr = nw_bc + + # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 + HandlesExprCall._call_method_on_ptr(pool, builder, mod, class_name, + "__before_init__", storage_ptr, None, 0, trans, diag_node_ct) + + # 如果有 __init__,调用 __init__(ptr, args...) + # 注意: 仅依据 ctor_entry.HasInit 判断,不强制推断 + # (JsonValue 等类有 __new__ 但无 __init__,强制推断会导致 undefined reference) + has_init_flag: int = 0 + if ctor_entry is not None: + has_init_flag = ctor_entry.HasInit + if has_init_flag != 0: + # 翻译构造函数参数 + arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if arg_vals is not None: + string.memset(arg_vals, 0, 8 * 32) + real_arg_count: int = 0 + for ai in range(can): + arg_node: ast.AST | t.CPtr = cargs.get(ai) + if arg_node is None: + continue + av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + if av is not None: + if real_arg_count < 32: + arg_vals[real_arg_count] = t.CSizeT(av) + real_arg_count += 1 + + HandlesExprCall._call_method_on_ptr(pool, builder, mod, class_name, + "__init__", storage_ptr, arg_vals, real_arg_count, trans, diag_node_ct) + elif has_new_flag == 0: + # 无 __init__ 且无 __new__:逐字段 store 参数值 + # (有 __new__ 时参数已由 __new__ 消费,不应存入字段) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + # fast-fail: 参数翻译失败 + VLogger.error( + f"构造函数参数翻译失败: {class_name}", + "HandlesExprCall") + continue + fe: HandlesStruct.FieldEntry | t.CPtr = None + if ctor_entry is not None: + # OOP 结构体字段表第 0 个字段是 __vtable__(vtable 指针占位), + # 构造参数按"用户字段顺序"存储:必须跳过 __vtable__ 字段, + # 否则参数会覆盖 vtable 槽(对象头读到垃圾指针, + # isinstance 的 icmp 全部不匹配 + 方法分派错乱)。 + # 原实现直接 _get_field_entry(ctor_entry, ai) 取到 __vtable__ + # → GEP Index 0 → 覆盖 vtable(Dog("dog") 场景崩溃漂移根因)。 + target_idx: int = 0 + for fi in range(ctor_entry.FieldCount): + cand_fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( + ctor_entry, fi) + if cand_fe is None: + continue + cand_name: str = HandlesStruct.get_field_name_ptr(cand_fe) + if cand_name is not None and string.strcmp(cand_name, "__vtable__") == 0: + continue + if target_idx == ai: + fe = cand_fe + break + target_idx += 1 + else: + fe = HandlesStruct.get_field_by_index(class_name, ai) + if fe is None: + # fast-fail: 字段索引越界(用户传了多余参数) + VLogger.error( + f"构造函数参数过多,字段索引越界: {class_name}", + "HandlesExprCall") + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, storage_ptr, fe.Index) + if field_ptr is None: + # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) + VLogger.error( + f"构造函数字段 GEP 失败: {class_name}", + "HandlesExprCall") + continue + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) + llvmlite.build_store(builder, arg_val, field_ptr) + + # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load + return storage_ptr + + # 普通结构体:先 store zeroinitializer 清零(确保未赋值字段为零) + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + llvmlite.build_store(builder, zero, tmp) + + # 应用默认值(显式参数会覆盖默认值) + self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) + + # 逐字段 store 参数值(覆盖默认值) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + # fast-fail: 参数翻译失败 + VLogger.error( + f"构造函数参数翻译失败: {class_name}", + "HandlesExprCall") + continue + # 获取字段信息(用 ctor_entry 规避跨模块同名 find_struct 找错) + fe: HandlesStruct.FieldEntry | t.CPtr = None + if ctor_entry is not None: + fe = HandlesStruct._get_field_entry(ctor_entry, ai) + else: + fe = HandlesStruct.get_field_by_index(class_name, ai) + if fe is None: + # fast-fail: 字段索引越界(用户传了多余参数) + VLogger.error( + f"构造函数参数过多,字段索引越界: {class_name}", + "HandlesExprCall") + continue + # GEP 到字段 ai + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) + VLogger.error( + f"构造函数字段 GEP 失败: {class_name}", + "HandlesExprCall") + continue + # 类型转换并 store + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) + llvmlite.build_store(builder, arg_val, field_ptr) + + # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load + return tmp + # ============================================================ + # _translate_renum_construct — REnum 变体构造函数 + # + # 语法: ClassName.VariantName(args...) + # 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体,__tag=0,_p1=1 + # + # 生成 IR: + # %tmp = alloca {i32, i32, ...} ; REnum 类型 + # store zeroinitializer, %tmp ; 清零 + # %tag_ptr = gep %tmp, 0, 0 ; __tag 字段 + # store i32 , %tag_ptr ; 写入 tag + # %p1_ptr = gep %tmp, 0, 1 ; _p1 字段 + # store , %p1_ptr ; 写入 payload[0] + # ... (更多 payload 字段) + # return %tmp ; 返回指针 + # + # 对应 TPC 的 _HandleREnumConstructLlvm + # ============================================================ + + # ============================================================ + # _translate_renum_construct — REnum 变体构造函数 + # + # 语法: ClassName.VariantName(args...) + # 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体,__tag=0,_p1=1 + # + # 生成 IR: + # %tmp = alloca {i32, i32, ...} ; REnum 类型 + # store zeroinitializer, %tmp ; 清零 + # %tag_ptr = gep %tmp, 0, 0 ; __tag 字段 + # store i32 , %tag_ptr ; 写入 tag + # %p1_ptr = gep %tmp, 0, 1 ; _p1 字段 + # store , %p1_ptr ; 写入 payload[0] + # ... (更多 payload 字段) + # return %tmp ; 返回指针 + # + # 对应 TPC 的 _HandleREnumConstructLlvm + # ============================================================ + def _translate_renum_construct(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + variant_name: str, + tag_value: int, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """构造 REnum 变体实例,返回指向 alloca 的指针 + + class_name: REnum 类名(如 "LLVMType") + variant_name: 变体名(如 "Int") + tag_value: 变体的 tag 值(变体在类中的索引) + cargs: 参数 AST 列表 + can: 参数数量 + """ + if pool is None or builder is None or class_name is None: + return None + + # 查找 REnum 结构体类型(用 find_struct_by_module 规避跨模块同名) + renum_entry: HandlesStruct.StructEntry | t.CPtr = None + if trans is not None: + renum_entry = HandlesStruct.find_struct_by_module(class_name, trans.ModuleSha1) + if renum_entry is None: + renum_entry = HandlesStruct.find_struct(class_name) + if renum_entry is None: + fb_re: str = VLogger.fmt_buf() + if fb_re is not None: + viperlib.snprintf(fb_re, 1024, "REnum construct: type %s not registered", class_name) + VLogger.error(fb_re, "RENUM") + return None + + renum_ty: llvmlite.LLVMType | t.CPtr = renum_entry.Ty + if renum_ty is None: + return None + + # alloca REnum 类型 + # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) + HandlesStruct.ensure_struct_def_in_module(pool, mod, renum_ty) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, renum_ty) + if tmp is None: + return llvmlite.ConstZero(pool, renum_ty) + + # 清零(确保未赋值的 payload 位置为零) + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, renum_ty) + llvmlite.build_store(builder, zero, tmp) + + # 写入 __tag 字段(索引 0) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + tag_name_buf: str = pool.alloc(32) + if tag_name_buf is not None: + viperlib.snprintf(tag_name_buf, 32, "%d", tag_value) + tag_const: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, i32_ty, tag_value, + tag_name_buf if tag_name_buf is not None else "0") + tag_field: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(renum_entry, 0) + tag_field_ty: llvmlite.LLVMType | t.CPtr = i32_ty + if tag_field is not None and tag_field.Ty is not None: + tag_field_ty = tag_field.Ty + tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, renum_ty, tag_field_ty, tmp, 0) + if tag_ptr is not None: + llvmlite.build_store(builder, tag_const, tag_ptr) + + # 写入 payload 字段(索引 1, 2, ... 对应 _p1, _p2, ...) + # 参数按位置顺序填充 payload,跳过 __tag(索引 0) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + continue + # payload 字段索引 = ai + 1(跳过 __tag) + payload_idx: int = ai + 1 + if payload_idx >= renum_entry.FieldCount: + break + pfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( + renum_entry, payload_idx) + if pfe is None: + continue + payload_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, renum_ty, pfe.Ty, tmp, payload_idx) + if payload_ptr is None: + continue + # 类型转换并 store(payload 位置可能是 i32 或 i64,按字段类型 coerce) + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, pfe.Ty, arg) + llvmlite.build_store(builder, arg_val, payload_ptr) + + # 返回指针(与 _translate_struct_ctor 一致,赋值时由 coerce_to_type 决定是否 load) + return tmp + # ============================================================ + # _translate_struct_ctor_kw — 结构体构造函数(关键字参数) + # + # 支持两种语法: + # Point(x=10, y=20) — 全关键字 + # Point(10, y=20) — 混合(位置 + 关键字) + # + # 位置参数按字段索引赋值,关键字参数按字段名查找赋值 + # ============================================================ + + # ============================================================ + # _translate_struct_ctor_kw — 结构体构造函数(关键字参数) + # + # 支持两种语法: + # Point(x=10, y=20) — 全关键字 + # Point(10, y=20) — 混合(位置 + 关键字) + # + # 位置参数按字段索引赋值,关键字参数按字段名查找赋值 + # ============================================================ + def _translate_struct_ctor_kw(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + struct_ty: llvmlite.LLVMType | t.CPtr, + class_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + keywords: list[ast.AST | t.CPtr] | t.CPtr, + kw_count: t.CSizeT, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """结构体构造函数(关键字参数版本)""" + # 创建临时 alloca + # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) + HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return llvmlite.ConstZero(pool, struct_ty) + # 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的 + # fatal_error 显示构造调用行号(本函数无 cl 参数,实参节点最接近调用点) + diag_node_ct: ast.AST | t.CPtr = None + if cargs is not None and len(cargs) > 0: + diag_node_ct = cargs.get(0) + + # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 + # 用 find_struct_by_type 规避跨模块同名 find_struct 找错 + kw_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) + is_oop: int = 0 + if kw_entry is not None: + is_oop = kw_entry.IsOOP + + # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) + # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) + # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) + if is_oop == 0 and class_name is not None: + kw_init_lookup: str = pool.alloc(128) + if kw_init_lookup is not None: + viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name) + # 方案1: 检查当前模块的函数声明 + kw_init_found: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, kw_init_lookup) + if kw_init_found is not None: + is_oop = 1 + if kw_entry is not None: + kw_entry.IsOOP = 1 + kw_entry.HasInit = 1 + else: + # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) + kw_init_defaults: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(kw_init_lookup) + if kw_init_defaults is not None: + is_oop = 1 + if kw_entry is not None: + kw_entry.IsOOP = 1 + kw_entry.HasInit = 1 + + if is_oop != 0: + HandlesExprCall._call_method_on_ptr(pool, builder, mod, class_name, + "__before_init__", tmp, None, 0, trans) + else: + # 普通结构体:store zeroinitializer + 应用默认值 + zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) + llvmlite.build_store(builder, zero, tmp) + self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) + + # OOP 结构体且有 __init__:调用 __init__ 而非逐字段 store + # 关键字构造调用此前总是逐字段 store,导致 __init__ 方法体不执行 + # (如 self._args = mb.alloc(...) 不执行 → self._args 为 NULL → add_argument 崩溃) + has_init_flag: int = 0 + has_new_flag: int = 0 + if kw_entry is not None: + has_init_flag = kw_entry.HasInit + has_new_flag = kw_entry.HasNew + + # 跨模块 OOP 类: HasInit 可能未设置(_translate_oop_methods 未被调用) + # 但 IsOOP=1 说明类有方法,推断 HasInit=1(__init__ 在目标模块中存在) + # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) + if is_oop != 0 and has_init_flag == 0: + has_init_flag = 1 + + if is_oop != 0 and has_init_flag != 0: + # 有 __init__:构建参数数组并调用 __init__ + storage_ptr: llvmlite.Value | t.CPtr = tmp + + # 如果有 __new__,调用 __new__ 获取实际存储指针 + if has_new_flag != 0: + new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if new_arg_vals is not None: + string.memset(new_arg_vals, 0, 8 * 32) + new_arg_count: int = 0 + for nai in range(can): + new_arg_node: ast.AST | t.CPtr = cargs.get(nai) + if new_arg_node is None: + continue + new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, new_arg_node, None, 0, trans) + if new_av is not None: + if new_arg_count < 32: + new_arg_vals[new_arg_count] = t.CSizeT(new_av) + new_arg_count += 1 + # 关键字参数也传递给 __new__ + for nki in range(kw_count): + nkw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(nki)) + if nkw is None or nkw.value is None: + continue + nkw_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, nkw.value, None, 0, trans) + if nkw_av is not None: + if new_arg_count < 32: + new_arg_vals[new_arg_count] = t.CSizeT(nkw_av) + new_arg_count += 1 + new_ptr: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( + pool, builder, mod, class_name, + "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct) + if new_ptr is not None: + storage_ptr = new_ptr + # __new__ 只保证返回"实例存储指针",声明类型通常是 + # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 + # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 + # obj.method(如 parser.add_argument)get_class_name_by_type + # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 + # bitcast 只改类型层视图,运行时零开销(指针位不变)。 + if new_ptr.Ty is not None: + nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): + nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) + if nw_bc is not None: + storage_ptr = nw_bc + + # 构建 __init__ 参数数组:位置参数按顺序 + 关键字参数追加 + init_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if init_arg_vals is not None: + string.memset(init_arg_vals, 0, 8 * 32) + init_arg_count: int = 0 + # 位置参数 + for ai_init in range(can): + arg_node_init: ast.AST | t.CPtr = cargs.get(ai_init) + if arg_node_init is None: + continue + av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg_node_init, None, 0, trans) + if av_init is not None: + if init_arg_count < 32: + init_arg_vals[init_arg_count] = t.CSizeT(av_init) + init_arg_count += 1 + # 关键字参数(追加到末尾,按出现顺序) + for ki_init in range(kw_count): + kw_init: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki_init)) + if kw_init is None or kw_init.value is None: + continue + kw_av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, kw_init.value, None, 0, trans) + if kw_av_init is not None: + if init_arg_count < 32: + init_arg_vals[init_arg_count] = t.CSizeT(kw_av_init) + init_arg_count += 1 + + # 调用 __init__(storage_ptr, *args) + HandlesExprCall._call_method_on_ptr(pool, builder, mod, class_name, + "__init__", storage_ptr, init_arg_vals, init_arg_count, trans, diag_node_ct) + + # 返回指针 + return storage_ptr + + # 无 __init__(或非 OOP):逐字段 store 参数值 + # 先处理位置参数(按字段索引,覆盖默认值) + for ai in range(can): + arg: ast.AST | t.CPtr = cargs.get(ai) + if arg is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + if arg_val is None: + continue + fe: HandlesStruct.FieldEntry | t.CPtr = None + if kw_entry is not None: + fe = HandlesStruct._get_field_entry(kw_entry, ai) + else: + fe = HandlesStruct.get_field_by_index(class_name, ai) + if fe is None: + # 位置参数越界(字段表无对应项):fail-fast,绝不静默跳过 + HandlesType.fatal_error( + arg, f"结构体 '{class_name}' 位置参数越界(无对应字段)", "TypeError") + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + continue + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) + llvmlite.build_store(builder, arg_val, field_ptr) + + # 处理关键字参数(按字段名查找) + # SHA1 从 kw_entry 获取(规避跨模块同名 find_struct 找错) + kw_sha1: str = None + if kw_entry is not None: + kw_sha1 = kw_entry.ModuleSha1 + for ki in range(kw_count): + kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) + if kw is None or kw.arg is None or kw.value is None: + continue + fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field_by_class( + class_name, kw.arg, kw_sha1) + if fe is None: + # 关键字字段不存在:fail-fast(AttributeError),绝不静默跳过 + HandlesType.fatal_error( + kw, f"结构体 '{class_name}' 无字段 '{kw.arg}'", "AttributeError") + continue + kw_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, kw.value, None, 0, trans) + if kw_val is None: + continue + field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, struct_ty, fe.Ty, tmp, fe.Index) + if field_ptr is None: + continue + kw_val = HandlesExpr.coerce_to_type(builder, kw_val, fe.Ty, kw.value) + llvmlite.build_store(builder, kw_val, field_ptr) + + # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load + return tmp + # ============================================================ + # _translate_t_type_cast - 翻译 t.XXX(value) 类型转换 + # + # 当 func 是 t.XXX 形式且 XXX 是已知类型名(map_t_type 能映射)时, + # 将 value 转换为目标类型: + # - 指针 → 整数: ptrtoint (如 t.CUInt64T(ptr) → i64) + # - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*) + # - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8) + # - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*) + # - 整数 → 浮点: sitofp (如 t.CDouble(i32_val) → double) + # - 浮点 → 整数: fptosi (如 t.CInt(double_val) → i32) + # - 浮点 → 浮点: fpext/fptrunc (如 t.CFloat(double_val) → float) + # ============================================================ + + # ============================================================ + # _translate_t_type_cast - 翻译 t.XXX(value) 类型转换 + # + # 当 func 是 t.XXX 形式且 XXX 是已知类型名(map_t_type 能映射)时, + # 将 value 转换为目标类型: + # - 指针 → 整数: ptrtoint (如 t.CUInt64T(ptr) → i64) + # - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*) + # - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8) + # - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*) + # - 整数 → 浮点: sitofp (如 t.CDouble(i32_val) → double) + # - 浮点 → 整数: fptosi (如 t.CInt(double_val) → i32) + # - 浮点 → 浮点: fpext/fptrunc (如 t.CFloat(double_val) → float) + # ============================================================ + def _translate_t_type_cast(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + val: llvmlite.Value | t.CPtr, + target_ty: llvmlite.LLVMType | t.CPtr, + target_name: str = None, + src_node: ast.AST | t.CPtr = None, + trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: + """类型转换:根据参数类型和目标类型选择转换方式 + + 整数 → 整数拓宽时(对齐 TPC _HandleTypeCastLlvm L1723-1737): + 源 i1(bool)→ zext + 目标类型无符号(target_name 命中 CUIntXXT 等)→ zext + 源表达式无符号(t.CUIntXXT(x) 强转 / 无符号注解变量)→ zext + 否则 → sext(有符号整数拓宽保持数值,如 i8 -50 → 0xFFFFFFCE) + """ + if val is None or target_ty is None: + return None + + val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty) + target_bits: int = HandlesExpr.get_llvm_type_bits(target_ty) + val_fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty) + target_fbits: int = HandlesExpr.get_llvm_float_bits(target_ty) + + # 整数 → 整数: trunc/zext/sext + if val_bits != 0 and target_bits != 0: + if val_bits == target_bits: + return val + elif val_bits < target_bits: + if val_bits == 1: + # i1 是布尔值(来自 icmp/fcmp),无符号语义,必须 zext + return llvmlite.build_zext(builder, val, target_ty) + # 目标类型名已知且为有符号 → 按源符号性 sext/zext(对齐 TPC L1723-1737); + # 目标名未知(int()/联合类型强转等)保持默认 zext(旧行为) + need_sext: int = 0 + if target_name is not None and HandlesExpr._type_name_unsigned(target_name) == 0: + if src_node is None or HandlesExpr._node_type_unsigned(pool, src_node, trans) == 0: + need_sext = 1 + if need_sext != 0: + return llvmlite.build_sext(builder, val, target_ty) + return llvmlite.build_zext(builder, val, target_ty) + else: + return llvmlite.build_trunc(builder, val, target_ty) + + # 整数 → 浮点: sitofp + if val_bits != 0 and target_fbits != 0: + return llvmlite.build_si2fp(builder, val, target_ty) + + # 浮点 → 整数: fptosi + if val_fbits != 0 and target_bits != 0: + return llvmlite.build_fp2si(builder, val, target_ty) + + # 浮点 → 浮点: fpext/fptrunc + if val_fbits != 0 and target_fbits != 0: + if val_fbits == target_fbits: + return val + elif val_fbits < target_fbits: + return llvmlite.build_fpext(builder, val, target_ty) + else: + return llvmlite.build_fptrunc(builder, val, target_ty) + + # 指针 → 整数: ptrtoint + if val_bits == 0 and val_fbits == 0 and target_bits != 0: + return llvmlite.build_ptrtoint(builder, val, target_ty) + + # 整数 → 指针: inttoptr(必须排除浮点 target,浮点 target_bits 也是 0) + if val_bits != 0 and target_bits == 0 and target_fbits == 0: + return llvmlite.build_inttoptr(builder, val, target_ty) + + # 指针 → 指针: bitcast + return llvmlite.build_bitcast(builder, val, target_ty) + # ============================================================ + # 泛型实例化辅助:从 Subscript slice 提取类型实参名 + # ============================================================ + # _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) + # HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 + + + # ============================================================ + # 泛型实例化辅助:从 Subscript slice 提取类型实参名 + # ============================================================ + # _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) + # HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 + + def _extract_type_args_from_slice(self, pool: memhub.MemBuddy | t.CPtr, + slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr: + """从 Subscript.slice 提取类型实参名列表 + + list[int] -> ["int"] + dict[str, int] -> ["str", "int"] + list[AST | t.CPtr] -> ["AST|t.CPtr"] + """ + if slice_node is None or pool is None: + return None + # elem_size=8:str 是 i8* 指针(8 字节),若用 4 则双元素时 append 写 8 字节 + # 但步长按 4 计算,第 2 个元素覆盖第 1 个元素高 4 字节 → get 读出垃圾指针崩溃 + result: list[str] | t.CPtr = list[str](pool, 8) + k: int = slice_node.kind() + if k == ast.ASTKind.Tuple: + tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(slice_node) + elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts + if elts is not None: + n: t.CSizeT = len(elts) + i: t.CSizeT + for i in range(n): + elt: ast.AST | t.CPtr = elts.get(i) + tn: str = HandlesType._get_type_name_from_annotation(pool, elt) + if tn is not None: + result.append(tn) + else: + tn: str = HandlesType._get_type_name_from_annotation(pool, slice_node) + if tn is not None: + result.append(tn) + return result + # ============================================================ + # 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__ + # + # 复用 translate_list_literal 的构造逻辑: + # 1. alloca tmp(特化类临时空间,作为 __new__ 的 self) + # 2. 翻译 cl.args 为参数指针数组 + # 3. call __new__(tmp, *args) → storage_ptr + # 4. call __before_init__(storage_ptr) + # 5. call __init__(storage_ptr, *args) + # 6. return storage_ptr + # + # 必须独立于 translate_call 的普通函数路径:spec_name 是类名不是函数名, + # 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1 + # 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。 + # ============================================================ + + # ============================================================ + # 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__ + # + # 复用 translate_list_literal 的构造逻辑: + # 1. alloca tmp(特化类临时空间,作为 __new__ 的 self) + # 2. 翻译 cl.args 为参数指针数组 + # 3. call __new__(tmp, *args) → storage_ptr + # 4. call __before_init__(storage_ptr) + # 5. call __init__(storage_ptr, *args) + # 6. return storage_ptr + # + # 必须独立于 translate_call 的普通函数路径:spec_name 是类名不是函数名, + # 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1 + # 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。 + # ============================================================ + def _infer_generic_ctor_type_arg(self, pool: memhub.MemBuddy | t.CPtr, + arg_node: ast.AST | t.CPtr, + class_name: str) -> str: + """从构造实参 AST 推断泛型类型实参名;无法推断时 fail-fast(绝不默认 "int") + + 裸名泛型类构造(Box(42) → Box[int])需要从实参推断类型实参。 + 对应 TPC _HandleGenericClassNewLlvm 的推断逻辑(常量/类型转换调用)。 + 注意:本函数仅做 AST 静态推断,不发射 IR(避免重复翻译实参)。 + """ + if pool is None or arg_node is None: + HandlesType.fatal_error( + None, + f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)", + "TypeError") + return "int" + k: int = arg_node.kind() + # 常量: 42→int, 3.14→double, "abc"→str + if k == ast.ASTKind.Constant: + cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg_node) + if cn.const_kind == ast.CONST_FLOAT: + return "double" + if cn.const_kind == ast.CONST_STR: + return "str" + return "int" + # 类型转换调用: int(...)/float(...)/t.CInt(...)/t.CDouble(...) + if k == ast.ASTKind.Call: + cl_f: ast.Call | t.CPtr = (ast.Call | t.CPtr)(arg_node) + if cl_f.func is not None: + if cl_f.func.kind() == ast.ASTKind.Name: + fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_f.func) + if fn_nm.id is not None: + # 与下方 Attribute 分支的 strstr 匹配一致:from t import CInt + # 后 `CInt(0)` 的 func 是 Name("CInt"),仅精确匹配 int/float + # 会漏判 → fail-fast 误杀(VectorGenericTest 隐式泛型推断)。 + if string.strcmp(fn_nm.id, "float") == 0 or string.strcmp(fn_nm.id, "double") == 0 \ + or string.strstr(fn_nm.id, "Float") is not None or string.strstr(fn_nm.id, "Double") is not None: + return "double" + if string.strcmp(fn_nm.id, "int") == 0 \ + or string.strstr(fn_nm.id, "Int") is not None or string.strstr(fn_nm.id, "UInt") is not None \ + or string.strstr(fn_nm.id, "Char") is not None or string.strstr(fn_nm.id, "Short") is not None \ + or string.strstr(fn_nm.id, "Long") is not None: + return "int" + elif cl_f.func.kind() == ast.ASTKind.Attribute: + fn_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_f.func) + if fn_at.attr is not None: + if string.strstr(fn_at.attr, "Float") is not None or string.strstr(fn_at.attr, "Double") is not None: + return "double" + if string.strstr(fn_at.attr, "Int") is not None or string.strstr(fn_at.attr, "UInt") is not None or string.strstr(fn_at.attr, "Char") is not None or string.strstr(fn_at.attr, "Short") is not None or string.strstr(fn_at.attr, "Long") is not None: + return "int" + # 类型转换调用(Call)但函数名无法识别:明确的类型意图却无法解析, + # fail-fast(区别于普通变量 Name——那是非 T 参数,默认 int 被过滤)。 + HandlesType.fatal_error( + arg_node, + f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)", + "TypeError") + return "int" + # 非类型转换节点(普通变量 Name/Attribute 等,如 Vector(pool, 8, ...) + # 的 pool 参数):不是 T 类型提示,返回默认 "int"(调用方"过滤纯 int" + # 逻辑将其排除,只保留 float/str 等区分性提示)。 + return "int" + def _translate_generic_ctor_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + spec_name: str, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__""" + if pool is None or builder is None or mod is None or spec_name is None or cl is None: + return None + + # 查找 struct entry 获取类型 + struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) + if struct_entry is None: + HandlesType.fatal_error(cl, "泛型类构造调用: 特化类未注册") + return None + struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty + if struct_ty is None: + return None + + # 确保结构体定义在当前模块中可用(供 alloca 分配空间) + HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) + + # alloca tmp(self 指针) + tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) + if tmp is None: + return None + + # 翻译 cl.args 为参数指针数组(extra_args[i] = Value 指针) + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = len(cargs) + + extra_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) + if extra_args is None: + return None + string.memset(extra_args, 0, 8 * 32) + + ai: t.CSizeT = 0 + while ai < can: + if ai >= 32: + # 定长 8*32 槽:超过 32 个实参继续写会越界污染 pool 相邻块,fail-fast + HandlesType.fatal_error( + cl, "泛型构造实参超过 32 个上限", "TypeError") + break + arg_node: ast.AST | t.CPtr = cargs.get(ai) + if arg_node is not None: + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + if arg_val is not None: + extra_args[ai] = t.CSizeT(arg_val) + ai += 1 + + # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 + # __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用 + # (与 _translate_struct_ctor 保持一致,避免为无 __new__ 的类生成过度声明) + storage_ptr: llvmlite.Value | t.CPtr = tmp + has_new_flag: int = 0 + if struct_entry is not None: + has_new_flag = struct_entry.HasNew + if has_new_flag != 0: + new_ptr: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__new__", tmp, extra_args, can, trans) + if new_ptr is not None: + storage_ptr = new_ptr + # __new__ 只保证返回"实例存储指针",声明类型通常是 + # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 + # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 + # obj.method(如 parser.add_argument)get_class_name_by_type + # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 + # bitcast 只改类型层视图,运行时零开销(指针位不变)。 + if new_ptr.Ty is not None: + nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) + if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): + nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) + if nw_bc is not None: + storage_ptr = nw_bc + + # call __before_init__(storage_ptr)(TransPyV 自动生成,零值填充) + HandlesExprCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans) + + # call __init__(storage_ptr, *args) + HandlesExprCall._call_method_on_ptr( + pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, can, trans) + + return storage_ptr \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenFd.vp b/App/lib/core/Gen/CallGenFd.vp new file mode 100644 index 0000000..699f28a --- /dev/null +++ b/App/lib/core/Gen/CallGenFd.vp @@ -0,0 +1,437 @@ +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.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + +# ============================================================ +# CallGenFd - CallGenMixin 拆分(阶段 B):FakeDuck / requires 字段注入 / provider 栈 +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenFd(CallGenBase.CallGenBase): + """FakeDuck / requires 字段注入 / provider 栈""" + + # ============================================================ + # _translate_fakeduck_call - FakeDuck: str 变量方法调用 → 扩展类 _Type/_str + # + # 对齐 TPC HandlesExprCall.py L2841-2880: + # ClassName 常规解析失败且对象是 char*(i8*)时,遍历扩展类查找 + # {CN}.{method} 函数。对象是 Name 变量且有影子({var}__meta__,fd2 + # 创建)时 self=影子;否则(字符串字面量/匿名 str)在入口创建临时 + # 影子,写 __data__=obj 值、__mbuddy__=NULL 后作 self,避免 + # bitcast i8* → _str* 读取垃圾指针导致 ACCESS_VIOLATION。 + # ============================================================ + + # ============================================================ + # _translate_fakeduck_call - FakeDuck: str 变量方法调用 → 扩展类 _Type/_str + # + # 对齐 TPC HandlesExprCall.py L2841-2880: + # ClassName 常规解析失败且对象是 char*(i8*)时,遍历扩展类查找 + # {CN}.{method} 函数。对象是 Name 变量且有影子({var}__meta__,fd2 + # 创建)时 self=影子;否则(字符串字面量/匿名 str)在入口创建临时 + # 影子,写 __data__=obj 值、__mbuddy__=NULL 后作 self,避免 + # bitcast i8* → _str* 读取垃圾指针导致 ACCESS_VIOLATION。 + # ============================================================ + def _translate_fakeduck_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cls_name: str, + method_name: str, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """FakeDuck: str 变量方法调用解析到扩展类 _Type/_str,返回 call 结果或 None""" + if pool is None or builder is None or cl is None or trans is None: + return None + if method_name is None: + return None + # 仅对 str 类型触发(AnnotClassName == "str",对象是 char*); + # cls_name 为 None(表达式接收者解析失败)时也尝试 + if cls_name is not None and string.strcmp(cls_name, "str") != 0: + return None + if cl.func is None or cl.func.kind() != ast.ASTKind.Attribute: + return None + fd_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if fd_at is None or fd_at.value is None or fd_at.attr is None: + return None + if string.strcmp(fd_at.attr, method_name) != 0: + return None + # 候选扩展类:先 _Type(a.type_id())后 _str(a.upper() 等) + fd_func: llvmlite.Function | t.CPtr = None + fd_cls: str = None + fd_key: str = pool.alloc(160) + if fd_key is not None: + for fd_ci in range(2): + fd_cn: str = "_Type" + if fd_ci == 1: + fd_cn = "_str" + viperlib.snprintf(fd_key, 160, "%s.%s", fd_cn, method_name) + fd_func = self.find_func_in_module(mod, fd_key) + if fd_func is not None: + fd_cls = fd_cn + break + if fd_func is None or fd_cls is None: + return None + # 扩展类结构体必须已注册(GEP/临时影子需要类型) + fd_sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(fd_cls) + if fd_sty is None: + return None + # 扩展类字段数:有字段(_str)时 self 用影子结构体指针; + # 无字段(_Type)时 self 用对象值 bitcast 到扩展类指针(对齐 TPC L2856-2876) + fd_entry_fd: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(fd_sty) + fd_has_fields: int = 0 + if fd_entry_fd is not None and fd_entry_fd.FieldCount > 0: + fd_has_fields = 1 + # self 参数:优先使用已有影子 {var}__meta__(fd2 创建,仅当扩展类有字段时) + fd_self: llvmlite.Value | t.CPtr = None + if fd_at.value.kind() == ast.ASTKind.Name: + fd_onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fd_at.value) + if fd_onm.id is not None: + # pool 持久缓冲(f-string 栈缓冲在函数返回后失效) + fd_mn: str = pool.alloc(256) + if fd_mn is not None: + viperlib.snprintf(fd_mn, 256, "%s__meta__", fd_onm.id) + fd_meta: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( + trans.SymTab, fd_mn) + if fd_meta is not None and fd_has_fields != 0: + fd_self = fd_meta + if fd_self is None: + if fd_has_fields != 0: + # 有字段扩展类且无影子(字符串字面量等):入口创建临时影子并初始化 + # 先确保 _str 完整定义(跨模块结构体默认 opaque,alloca 报 unsized) + HandlesStruct.ensure_struct_def_in_module(pool, mod, fd_sty) + fd_self = HandlesVar._alloca_at_entry(builder, fd_sty) + if fd_self is None: + return None + fd_obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, fd_at.value, None, 0, trans) + if fd_obj_val is not None: + fd_dfe: HandlesStruct.FieldEntry | t.CPtr = \ + HandlesStruct.lookup_field(fd_sty, "__data__") + if fd_dfe is not None and fd_dfe.Ty is not None: + fd_dp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, fd_sty, fd_dfe.Ty, fd_self, fd_dfe.Index) + if fd_dp is not None: + llvmlite.build_store(builder, fd_obj_val, fd_dp) + fd_bfe: HandlesStruct.FieldEntry | t.CPtr = \ + HandlesStruct.lookup_field(fd_sty, "__mbuddy__") + if fd_bfe is not None and fd_bfe.Ty is not None: + fd_bp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, fd_sty, fd_bfe.Ty, fd_self, fd_bfe.Index) + fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, fd_bfe.Ty, "null") + if fd_bp is not None and fd_null is not None: + llvmlite.build_store(builder, fd_null, fd_bp) + # FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__) + self._inject_requires_fields( + trans, pool, builder, mod, fd_self, fd_cls) + else: + # 无字段扩展类(_Type):对象值 bitcast 到扩展类指针 + fd_obj_v: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, fd_at.value, None, 0, trans) + if fd_obj_v is None: + return None + fd_self = llvmlite.build_bitcast( + builder, fd_obj_v, llvmlite.Ptr(pool, fd_sty)) + if fd_self is None: + return None + # 构建参数链表: self → 其余参数 + llvmlite.value_set_next(fd_self, None) + fd_head: llvmlite.Value | t.CPtr = fd_self + fd_tail: llvmlite.Value | t.CPtr = fd_self + fd_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args + fd_can: int = 0 + if fd_args is not None: + fd_can = len(fd_args) + for fd_ai in range(fd_can): + fd_arg: ast.AST | t.CPtr = fd_args.get(fd_ai) + if fd_arg is not None: + fd_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, fd_arg, None, 0, trans) + # char 常量参数 → 单字符字符串(char 隐式转 str, + # 如 s1.split(','):',' 是 i32 值 44,传给 str 参数须先字符串化, + # 否则运行时 strlen/strncmp 解引用 44 崩溃) + if fd_arg.kind() == ast.ASTKind.Constant: + fd_ac: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(fd_arg) + if fd_ac.const_kind == ast.CONST_CHAR: + ch_buf: str = pool.alloc(2) + if ch_buf is not None: + ch_buf[0] = t.CChar(fd_ac.int_val) + ch_buf[1] = '\0' + fd_av = HandlesExpr.create_global_string( + builder, pool, mod, ch_buf, trans) + if fd_av is not None: + llvmlite.value_set_next(fd_av, None) + llvmlite.value_set_next(fd_tail, fd_av) + fd_tail = fd_av + # 返回类型与调用名(来自 find_func_in_module 命中的函数定义) + fd_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fd_func) + if fd_ret_ty is None: + fd_ret_ty = llvmlite.Int32(pool) + fd_fname: str = llvmlite.function_get_name(fd_func) + if fd_fname is None: + return None + # 返回类型精确化:跨模块 declare 的 list[T] 特化返回类型可能被简化 + # 为 Ptr(i8),调用方变量 alloca 类型随之退化 → parts[0] 走字符下标 + # 路径而非 list 内联 __getitem__(printf %s 解引用字符值崩溃)。 + # 从定义模块 text.ll 读取精确返回类型(对齐普通方法调用 _translate_method_call)。 + fd_sha1: str = pool.alloc(17) + if fd_sha1 is not None: + string.strncpy(fd_sha1, fd_fname, 16) + fd_sha1[16] = '\0' + fd_exact: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( + pool, fd_sha1, fd_cls, method_name) + if fd_exact is not None: + fd_ret_ty = fd_exact + fd_total: int = 1 + fd_can + return llvmlite.build_call(builder, fd_fname, fd_head, fd_total, fd_ret_ty, 0) + # ============================================================ + # _inject_requires_fields - FakeDuck: with 上下文注入 requires 字段 + # + # 对齐 TPC HandlesExprCall.py L4021-4079: + # 对类 __requires__ 元数据(fd1 注册)中的每个字段,运行时调用 + # _find_provider(field) 查找 with 上下文提供的指针;非 NULL 时 + # bitcast 到字段类型写入 meta_ptr 对应槽位(条件注入,避免覆盖 + # 用户已手动设置的值)。_find_provider 未注册(未 import + # _withcontent)时跳过注入,不影响非 with 场景。 + # ============================================================ + + # ============================================================ + # _inject_requires_fields - FakeDuck: with 上下文注入 requires 字段 + # + # 对齐 TPC HandlesExprCall.py L4021-4079: + # 对类 __requires__ 元数据(fd1 注册)中的每个字段,运行时调用 + # _find_provider(field) 查找 with 上下文提供的指针;非 NULL 时 + # bitcast 到字段类型写入 meta_ptr 对应槽位(条件注入,避免覆盖 + # 用户已手动设置的值)。_find_provider 未注册(未 import + # _withcontent)时跳过注入,不影响非 with 场景。 + # ============================================================ + def _inject_requires_fields(self, trans: HT.Translator | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + meta_ptr: llvmlite.Value | t.CPtr, + class_name: str) -> int: + """在 with 上下文注入 requires 字段,返回注入字段数""" + if trans is None or pool is None or builder is None or mod is None: + return 0 + if meta_ptr is None or class_name is None: + return 0 + # _withcontent._find_provider(跨模块):仅当本模块可见(_withcontent + # 被 import,vpi stub declare 已注入)时才注入。对齐 TPC L4048-4050 + # (Gen.functions.get('_find_provider') 不存在则跳过)——否则非 with + # 项目(如 HashTableTest 未 import _withcontent)也会为每个 _str(...) + # 构造发射 {sha1}._find_provider 调用 → ld.lld undefined symbol。 + fd_fn_probe: llvmlite.Function | t.CPtr = self.find_func_in_module( + mod, "_find_provider") + if fd_fn_probe is None: + return 0 + fd_fname: str = llvmlite.function_get_name(fd_fn_probe) + if fd_fname is None: + return 0 + cnt: int = HandlesType.class_meta_count( + HandlesType.CLASS_META_REQUIRES, class_name) + if cnt <= 0: + return 0 + sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name) + if sty is None: + return 0 + i8_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + if i8_ty_j is None: + return 0 + i8_ptr_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_j) + if i8_ptr_ty_j is None: + return 0 + cur_func: llvmlite.Function | t.CPtr = trans._cur_func + if cur_func is None: + return 0 + injected: int = 0 + for ji in range(cnt): + fname: str = HandlesType.class_meta_field_at( + HandlesType.CLASS_META_REQUIRES, class_name, ji) + if fname is None: + continue + fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( + sty, fname) + if fe is None or fe.Ty is None: + continue + # 参数:字段名字符串(i8*) + fd_fstr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( + builder, pool, mod, fname, trans) + if fd_fstr is None: + continue + llvmlite.value_set_next(fd_fstr, None) + self._ensure_method_declare( + pool, mod, fd_fname, i8_ptr_ty_j, fd_fstr, 1) + fd_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call( + builder, fd_fname, fd_fstr, 1, i8_ptr_ty_j, 0) + if fd_ptr is None: + continue + # 条件注入:ptr != NULL 才写入(保留用户手动设置的值) + fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, i8_ptr_ty_j, "null") + if fd_null is None: + continue + fd_cmp: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, fd_ptr, fd_null) + if fd_cmp is None: + continue + # 块名唯一化(create_block 不自动编号,同名 label 在文本 IR 中 + # 冲突 → llc "Terminator found in the middle of a basic block") + vtc2: int = trans._label_counter + trans._label_counter = vtc2 + 1 + fd_bb_buf2: str = pool.alloc(64) + if fd_bb_buf2 is None: + continue + viperlib.snprintf(fd_bb_buf2, 64, "fd.skip.%d", vtc2) + fd_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, cur_func, fd_bb_buf2) + viperlib.snprintf(fd_bb_buf2, 64, "fd.inject.%d", vtc2) + fd_inject_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, cur_func, fd_bb_buf2) + if fd_skip_bb is None or fd_inject_bb is None: + continue + llvmlite.build_cond_br(builder, fd_cmp, fd_inject_bb, fd_skip_bb) + # inject 块:bitcast + GEP + store,跳回 skip + llvmlite.position_at_end(builder, fd_inject_bb) + fd_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, fd_ptr, fe.Ty) + if fd_cast is not None: + fd_fp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, sty, fe.Ty, meta_ptr, fe.Index) + if fd_fp is not None: + llvmlite.build_store(builder, fd_cast, fd_fp) + llvmlite.build_br(builder, fd_skip_bb) + # skip 块:恢复 CurBlock,继续后续代码生成 + llvmlite.position_at_end(builder, fd_skip_bb) + injected += 1 + return injected + # ============================================================ + # _emit_provider_push / _emit_provider_pop - FakeDuck: with 上下文 + # provider push/pop(__provides__ 元数据,fd1 注册) + # + # 对齐 TPC HandlesWith.py L138-174: + # with 进入时对每个提供字段生成 _push_provider(field_str, ctx_i8); + # 退出时生成等量 _pop_provider()。运行时 _withcontent 模块负责 + # 维护 TLS provider 栈,供 _inject_requires_fields 查找。 + # ============================================================ + + # ============================================================ + # _emit_provider_push / _emit_provider_pop - FakeDuck: with 上下文 + # provider push/pop(__provides__ 元数据,fd1 注册) + # + # 对齐 TPC HandlesWith.py L138-174: + # with 进入时对每个提供字段生成 _push_provider(field_str, ctx_i8); + # 退出时生成等量 _pop_provider()。运行时 _withcontent 模块负责 + # 维护 TLS provider 栈,供 _inject_requires_fields 查找。 + # ============================================================ + def _emit_provider_push(self, trans: HT.Translator | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cls_name: str, + ctx_val: llvmlite.Value | t.CPtr) -> int: + """生成 _push_provider(field, ctx_i8) 调用(每提供字段一次),返回字段数""" + if trans is None or pool is None or builder is None or mod is None: + return 0 + if cls_name is None or ctx_val is None: + return 0 + fd_pc: int = HandlesType.class_meta_count( + HandlesType.CLASS_META_PROVIDES, cls_name) + if fd_pc <= 0: + return 0 + # _withcontent._push_provider(跨模块,同 _find_provider 的可见性守卫: + # 本模块未 import _withcontent 时跳过,避免 undefined symbol) + fd_pfn_probe: llvmlite.Function | t.CPtr = self.find_func_in_module( + mod, "_push_provider") + if fd_pfn_probe is None: + return 0 + fd_pfn: str = llvmlite.function_get_name(fd_pfn_probe) + if fd_pfn is None: + return 0 + i8_ty_p: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + if i8_ty_p is None: + return 0 + i8_ptr_ty_p: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_p) + if i8_ptr_ty_p is None: + return 0 + ret_i32_p: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if ret_i32_p is None: + return 0 + # ctx 值 bitcast 到 i8*(provider 栈存 void*) + fd_ctx_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, ctx_val, i8_ptr_ty_p) + if fd_ctx_i8 is None: + return 0 + for pi in range(fd_pc): + fname: str = HandlesType.class_meta_field_at( + HandlesType.CLASS_META_PROVIDES, cls_name, pi) + if fname is None: + continue + fd_fstr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( + builder, pool, mod, fname, trans) + if fd_fstr is None: + continue + llvmlite.value_set_next(fd_fstr, fd_ctx_i8) + llvmlite.value_set_next(fd_ctx_i8, None) + self._ensure_method_declare( + pool, mod, fd_pfn, ret_i32_p, fd_fstr, 2) + llvmlite.build_call(builder, fd_pfn, fd_fstr, 2, ret_i32_p, 0) + return fd_pc + def _emit_provider_pop(self, trans: HT.Translator | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cls_name: str) -> int: + """生成 _pop_provider() 调用(每提供字段一次),返回字段数""" + if trans is None or pool is None or builder is None or mod is None: + return 0 + if cls_name is None: + return 0 + fd_pc: int = HandlesType.class_meta_count( + HandlesType.CLASS_META_PROVIDES, cls_name) + if fd_pc <= 0: + return 0 + # _withcontent._pop_provider(跨模块,同 _find_provider 的可见性守卫: + # 本模块未 import _withcontent 时跳过,避免 undefined symbol) + fd_pon_probe: llvmlite.Function | t.CPtr = self.find_func_in_module( + mod, "_pop_provider") + if fd_pon_probe is None: + return 0 + fd_pon: str = llvmlite.function_get_name(fd_pon_probe) + if fd_pon is None: + return 0 + ret_i32_q: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if ret_i32_q is None: + return 0 + self._ensure_method_declare(pool, mod, fd_pon, ret_i32_q, None, 0) + for _pi in range(fd_pc): + llvmlite.build_call(builder, fd_pon, None, 0, ret_i32_q, 0) + return fd_pc \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenMixin.vp b/App/lib/core/Gen/CallGenMixin.vp index 854d19b..304f5ac 100644 --- a/App/lib/core/Gen/CallGenMixin.vp +++ b/App/lib/core/Gen/CallGenMixin.vp @@ -500,3198 +500,30 @@ class CallGenMixin(CallGenBase.CallGenBase): return dst_coerced - # ============================================================ - # _apply_struct_defaults — 应用结构体字段的默认值 - # - # 在 zeroinitializer 之后、显式参数之前调用 - # 遍历所有字段,对有默认值的字段翻译并 store - # 显式参数(位置/关键字)后续会覆盖默认值 - # ============================================================ - def _apply_struct_defaults(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - tmp: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr): - """应用结构体字段的默认值""" - # 用类型指针定位 entry,规避跨模块同名 find_struct 找错 - entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - if entry is None: - # fast-fail: 结构体类型未注册,静默 return 会导致字段未初始化 - VLogger.error( - f"结构体类型未注册,无法应用默认值: {class_name}", - "HandlesExprCall") - return - for fi in range(entry.FieldCount): - fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - entry, fi) - if fe is None: - # fast-fail: 字段索引越界(entry.FieldCount 与实际不一致) - VLogger.error( - f"字段索引越界,无法获取字段 entry: {class_name}", - "HandlesExprCall") - continue - if fe.DefaultVal is None: - continue # 合理跳过:无默认值的字段 - # 静态数组字段 + 列表字面量默认值 → 整体置零 + 逐元素 GEP+store - # (与 _generate_before_init 一致;translate_value 会把列表字面量 - # 误译成动态 list 对象指针,coerce 到 [N x elem] 会失败)。 - # Mixin 静态绑定:跨 Mixin 方法必须走 HandlesAnnAssign 模块级委托。 - if fe.Ty is not None and HandlesExpr.is_array_type(fe.Ty) != 0 \ - and fe.DefaultVal.kind() == ast.ASTKind.List: - field_ptr_arr2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, tmp, fe.Index) - if field_ptr_arr2 is not None: - zero_arr2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, fe.Ty) - if zero_arr2 is not None: - llvmlite.build_store(builder, zero_arr2, field_ptr_arr2) - HandlesAnnAssign._init_global_array_from_list( - builder, pool, mod, field_ptr_arr2, fe.DefaultVal, trans) - continue - default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fe.DefaultVal, None, 0, trans) - if default_val is None: - # fast-fail: 默认值翻译失败(如引用了未定义符号) - VLogger.error( - f"字段默认值翻译失败: {class_name}", - "HandlesExprCall") - continue - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, tmp, fe.Index) - if field_ptr is None: - # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) - VLogger.error( - f"字段 GEP 失败,类型不匹配: {class_name}", - "HandlesExprCall") - continue - default_val = HandlesExpr.coerce_to_type(builder, default_val, fe.Ty, fe.DefaultVal) - llvmlite.build_store(builder, default_val, field_ptr) - # ============================================================ - # _translate_struct_ctor — 结构体构造函数 Point(10, 20) - # - # 生成: - # %tmp = alloca {i32, i32} - # store {i32, i32} zeroinitializer, {i32, i32}* %tmp - # %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0 - # store i32 10, i32* %f0 - # %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1 - # store i32 20, i32* %f1 - # %result = load {i32, i32}, {i32, i32}* %tmp - # ============================================================ - # ============================================================ - # _translate_struct_ctor — 结构体构造函数 Point(10, 20) - # - # 生成: - # %tmp = alloca {i32, i32} - # store {i32, i32} zeroinitializer, {i32, i32}* %tmp - # %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0 - # store i32 10, i32* %f0 - # %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1 - # store i32 20, i32* %f1 - # %result = load {i32, i32}, {i32, i32}* %tmp - # ============================================================ - def _translate_struct_ctor(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """结构体构造函数:按字段顺序 store 参数值,返回结构体值 - OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load - 普通结构体:alloca → zero + defaults → store 参数 → load - """ - # 创建临时 alloca - # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) - if tmp is None: - return llvmlite.ConstZero(pool, struct_ty) - # 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的 - # fatal_error 显示构造调用行号(本函数无 cl 参数,实参节点最接近调用点) - diag_node_ct: ast.AST | t.CPtr = None - if cargs is not None and len(cargs) > 0: - diag_node_ct = cargs.get(0) - # 检查是否为 OOP 结构体(用类型指针定位 entry,规避跨模块同名 find_struct 找错) - ctor_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - is_oop: int = 0 - if ctor_entry is not None: - is_oop = ctor_entry.IsOOP - # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) - # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) - # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) - if is_oop == 0 and class_name is not None: - init_lookup_name: str = pool.alloc(128) - if init_lookup_name is not None: - viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name) - # 方案1: 检查当前模块的函数声明 - init_found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, init_lookup_name) - if init_found_func is not None: - is_oop = 1 - if ctor_entry is not None: - ctor_entry.IsOOP = 1 - ctor_entry.HasInit = 1 - else: - # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) - init_defaults_entry: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(init_lookup_name) - if init_defaults_entry is not None: - is_oop = 1 - if ctor_entry is not None: - ctor_entry.IsOOP = 1 - ctor_entry.HasInit = 1 - if is_oop != 0: - # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 - storage_ptr: llvmlite.Value | t.CPtr = tmp - # 如果有 __new__,调用 __new__(tmp, args...) 获取实际存储指针 - # __new__ 签名与 __init__ 一样(self + args),返回 Ptr(struct_ty) - has_new_flag: int = 0 - if ctor_entry is not None: - has_new_flag = ctor_entry.HasNew - # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) - if has_new_flag != 0: - new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if new_arg_vals is not None: - string.memset(new_arg_vals, 0, 8 * 32) - new_arg_count: int = 0 - for nai in range(can): - new_arg_node: ast.AST | t.CPtr = cargs.get(nai) - if new_arg_node is None: - continue - new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, new_arg_node, None, 0, trans) - if new_av is not None: - if new_arg_count < 32: - new_arg_vals[new_arg_count] = t.CSizeT(new_av) - new_arg_count += 1 - new_ptr: llvmlite.Value | t.CPtr = self._call_method_on_ptr( - pool, builder, mod, class_name, - "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct) - if new_ptr is not None: - storage_ptr = new_ptr - # __new__ 只保证返回"实例存储指针",声明类型通常是 - # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 - # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 - # obj.method(如 parser.add_argument)get_class_name_by_type - # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 - # bitcast 只改类型层视图,运行时零开销(指针位不变)。 - if new_ptr.Ty is not None: - nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) - if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): - nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) - if nw_bc is not None: - storage_ptr = nw_bc - # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 - self._call_method_on_ptr(pool, builder, mod, class_name, - "__before_init__", storage_ptr, None, 0, trans, diag_node_ct) - # 如果有 __init__,调用 __init__(ptr, args...) - # 注意: 仅依据 ctor_entry.HasInit 判断,不强制推断 - # (JsonValue 等类有 __new__ 但无 __init__,强制推断会导致 undefined reference) - has_init_flag: int = 0 - if ctor_entry is not None: - has_init_flag = ctor_entry.HasInit - if has_init_flag != 0: - # 翻译构造函数参数 - arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if arg_vals is not None: - string.memset(arg_vals, 0, 8 * 32) - real_arg_count: int = 0 - for ai in range(can): - arg_node: ast.AST | t.CPtr = cargs.get(ai) - if arg_node is None: - continue - av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node, None, 0, trans) - if av is not None: - if real_arg_count < 32: - arg_vals[real_arg_count] = t.CSizeT(av) - real_arg_count += 1 - self._call_method_on_ptr(pool, builder, mod, class_name, - "__init__", storage_ptr, arg_vals, real_arg_count, trans, diag_node_ct) - elif has_new_flag == 0: - # 无 __init__ 且无 __new__:逐字段 store 参数值 - # (有 __new__ 时参数已由 __new__ 消费,不应存入字段) - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None: - # fast-fail: 参数翻译失败 - VLogger.error( - f"构造函数参数翻译失败: {class_name}", - "HandlesExprCall") - continue - fe: HandlesStruct.FieldEntry | t.CPtr = None - if ctor_entry is not None: - # OOP 结构体字段表第 0 个字段是 __vtable__(vtable 指针占位), - # 构造参数按"用户字段顺序"存储:必须跳过 __vtable__ 字段, - # 否则参数会覆盖 vtable 槽(对象头读到垃圾指针, - # isinstance 的 icmp 全部不匹配 + 方法分派错乱)。 - # 原实现直接 _get_field_entry(ctor_entry, ai) 取到 __vtable__ - # → GEP Index 0 → 覆盖 vtable(Dog("dog") 场景崩溃漂移根因)。 - target_idx: int = 0 - for fi in range(ctor_entry.FieldCount): - cand_fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - ctor_entry, fi) - if cand_fe is None: - continue - cand_name: str = HandlesStruct.get_field_name_ptr(cand_fe) - if cand_name is not None and string.strcmp(cand_name, "__vtable__") == 0: - continue - if target_idx == ai: - fe = cand_fe - break - target_idx += 1 - else: - fe = HandlesStruct.get_field_by_index(class_name, ai) - if fe is None: - # fast-fail: 字段索引越界(用户传了多余参数) - VLogger.error( - f"构造函数参数过多,字段索引越界: {class_name}", - "HandlesExprCall") - continue - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, storage_ptr, fe.Index) - if field_ptr is None: - # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) - VLogger.error( - f"构造函数字段 GEP 失败: {class_name}", - "HandlesExprCall") - continue - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) - llvmlite.build_store(builder, arg_val, field_ptr) - # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load - return storage_ptr - # 普通结构体:先 store zeroinitializer 清零(确保未赋值字段为零) - zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) - llvmlite.build_store(builder, zero, tmp) - # 应用默认值(显式参数会覆盖默认值) - self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) - # 逐字段 store 参数值(覆盖默认值) - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None: - # fast-fail: 参数翻译失败 - VLogger.error( - f"构造函数参数翻译失败: {class_name}", - "HandlesExprCall") - continue - # 获取字段信息(用 ctor_entry 规避跨模块同名 find_struct 找错) - fe: HandlesStruct.FieldEntry | t.CPtr = None - if ctor_entry is not None: - fe = HandlesStruct._get_field_entry(ctor_entry, ai) - else: - fe = HandlesStruct.get_field_by_index(class_name, ai) - if fe is None: - # fast-fail: 字段索引越界(用户传了多余参数) - VLogger.error( - f"构造函数参数过多,字段索引越界: {class_name}", - "HandlesExprCall") - continue - # GEP 到字段 ai - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, tmp, fe.Index) - if field_ptr is None: - # fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配) - VLogger.error( - f"构造函数字段 GEP 失败: {class_name}", - "HandlesExprCall") - continue - # 类型转换并 store - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) - llvmlite.build_store(builder, arg_val, field_ptr) - # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load - return tmp - # ============================================================ - # _translate_renum_construct — REnum 变体构造函数 - # - # 语法: ClassName.VariantName(args...) - # 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体,__tag=0,_p1=1 - # - # 生成 IR: - # %tmp = alloca {i32, i32, ...} ; REnum 类型 - # store zeroinitializer, %tmp ; 清零 - # %tag_ptr = gep %tmp, 0, 0 ; __tag 字段 - # store i32 , %tag_ptr ; 写入 tag - # %p1_ptr = gep %tmp, 0, 1 ; _p1 字段 - # store , %p1_ptr ; 写入 payload[0] - # ... (更多 payload 字段) - # return %tmp ; 返回指针 - # - # 对应 TPC 的 _HandleREnumConstructLlvm - # ============================================================ - # ============================================================ - # _translate_renum_construct — REnum 变体构造函数 - # - # 语法: ClassName.VariantName(args...) - # 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体,__tag=0,_p1=1 - # - # 生成 IR: - # %tmp = alloca {i32, i32, ...} ; REnum 类型 - # store zeroinitializer, %tmp ; 清零 - # %tag_ptr = gep %tmp, 0, 0 ; __tag 字段 - # store i32 , %tag_ptr ; 写入 tag - # %p1_ptr = gep %tmp, 0, 1 ; _p1 字段 - # store , %p1_ptr ; 写入 payload[0] - # ... (更多 payload 字段) - # return %tmp ; 返回指针 - # - # 对应 TPC 的 _HandleREnumConstructLlvm - # ============================================================ - def _translate_renum_construct(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - variant_name: str, - tag_value: int, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """构造 REnum 变体实例,返回指向 alloca 的指针 - class_name: REnum 类名(如 "LLVMType") - variant_name: 变体名(如 "Int") - tag_value: 变体的 tag 值(变体在类中的索引) - cargs: 参数 AST 列表 - can: 参数数量 - """ - if pool is None or builder is None or class_name is None: - return None - # 查找 REnum 结构体类型(用 find_struct_by_module 规避跨模块同名) - renum_entry: HandlesStruct.StructEntry | t.CPtr = None - if trans is not None: - renum_entry = HandlesStruct.find_struct_by_module(class_name, trans.ModuleSha1) - if renum_entry is None: - renum_entry = HandlesStruct.find_struct(class_name) - if renum_entry is None: - fb_re: str = VLogger.fmt_buf() - if fb_re is not None: - viperlib.snprintf(fb_re, 1024, "REnum construct: type %s not registered", class_name) - VLogger.error(fb_re, "RENUM") - return None - renum_ty: llvmlite.LLVMType | t.CPtr = renum_entry.Ty - if renum_ty is None: - return None - # alloca REnum 类型 - # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, mod, renum_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, renum_ty) - if tmp is None: - return llvmlite.ConstZero(pool, renum_ty) - # 清零(确保未赋值的 payload 位置为零) - zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, renum_ty) - llvmlite.build_store(builder, zero, tmp) - # 写入 __tag 字段(索引 0) - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - tag_name_buf: str = pool.alloc(32) - if tag_name_buf is not None: - viperlib.snprintf(tag_name_buf, 32, "%d", tag_value) - tag_const: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, i32_ty, tag_value, - tag_name_buf if tag_name_buf is not None else "0") - tag_field: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(renum_entry, 0) - tag_field_ty: llvmlite.LLVMType | t.CPtr = i32_ty - if tag_field is not None and tag_field.Ty is not None: - tag_field_ty = tag_field.Ty - tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, renum_ty, tag_field_ty, tmp, 0) - if tag_ptr is not None: - llvmlite.build_store(builder, tag_const, tag_ptr) - - # 写入 payload 字段(索引 1, 2, ... 对应 _p1, _p2, ...) - # 参数按位置顺序填充 payload,跳过 __tag(索引 0) - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None: - continue - # payload 字段索引 = ai + 1(跳过 __tag) - payload_idx: int = ai + 1 - if payload_idx >= renum_entry.FieldCount: - break - pfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - renum_entry, payload_idx) - if pfe is None: - continue - payload_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, renum_ty, pfe.Ty, tmp, payload_idx) - if payload_ptr is None: - continue - # 类型转换并 store(payload 位置可能是 i32 或 i64,按字段类型 coerce) - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, pfe.Ty, arg) - llvmlite.build_store(builder, arg_val, payload_ptr) - - # 返回指针(与 _translate_struct_ctor 一致,赋值时由 coerce_to_type 决定是否 load) - return tmp - - # ============================================================ - # _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 — 返回类型 - # ============================================================ - - # ============================================================ - # _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 找错) - vc_entry: HandlesStruct.StructEntry | t.CPtr = None - struct_ty: llvmlite.LLVMType | t.CPtr = None - if self_ptr.Ty is not None: - vc_entry = HandlesStruct.get_struct_type_from_value(self_ptr) - if vc_entry is not None: - # vc_entry 是 struct_ty(LLVMType),需要找 StructEntry - vc_entry = HandlesStruct.find_struct_by_type(vc_entry) - if vc_entry is not None: - struct_ty = vc_entry.Ty - if struct_ty is None: - struct_ty = HandlesStruct.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 = HandlesStruct.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 = HandlesStruct.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 指针为首个参数 - # 如果该方法在虚表中,则走虚方法分发路径(间接调用) - # ============================================================ - - # ============================================================ - # _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: HandlesStruct.StructEntry | t.CPtr = None - cmop_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(self_ptr) - if cmop_struct_ty is not None: - cmop_entry = HandlesStruct.find_struct_by_type(cmop_struct_ty) - if cmop_entry is None: - cmop_entry = HandlesStruct.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 = HandlesStruct.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) - HandlesType.fatal_error(node, err_msg) - HandlesType.fatal_error(node, "找不到模块 SHA1") - mangled_len2: t.CSizeT = string.strlen(cls_sha1) + string.strlen(lookup_name) + 2 - mangled2: str = pool.alloc(mangled_len2) - if mangled2 is not None: - viperlib.snprintf(mangled2, mangled_len2, "%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) - HandlesType.fatal_error(node, err_cm1) - HandlesType.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) - HandlesType.fatal_error(node, err_cm2) - HandlesType.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) - HandlesType.fatal_error(node, err_cm3) - HandlesType.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 未生成(方法定义模块尚未翻译)→ 标记重试, - # 保持 void 继续(对齐 _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 - call_ret_ty = llvmlite.Void(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) - HandlesType.fatal_error(node, err_cm4) - HandlesType.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: FuncEntry | t.CPtr = HandlesExprCall.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: FuncDefaultsEntry | t.CPtr = HandlesExprCall.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 - - # 计算需要填充的参数(不含 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 = HandlesExprCall._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__ 报错行号丢失根因) - HandlesType.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 - 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 = HandlesExpr.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) - - return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0) - - # ============================================================ - # _ensure_method_declare - 为跨模块方法调用创建 declare 声明 - # - # 当 found_func 为 None(stub 未注入或跨模块调用)时, - # 在当前模块中创建函数声明,避免 llc 报 undefined value。 - # ============================================================ - - # ============================================================ - # 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助 - # - # 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充, - # 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method() - # 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。 - # ============================================================ - - # ============================================================ - # _translate_property_call — 翻译属性方法调用 - # - # 与 _translate_method_call 的调用名/返回类型解析逻辑一致: - # 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入) - # 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名 - # 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32) - # - # call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数) - # ============================================================ - def _translate_property_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - method_name: str, - call_head: llvmlite.Value | t.CPtr, - call_count: int, - 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 - - # 构造查找名: 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) - - # 查找函数(精确/后缀匹配) - 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: - # 未找到:用类所属模块的 SHA1 构造调用名 - cls_sha1_pc: str = HandlesStruct.get_struct_sha1(class_name) - if cls_sha1_pc is not None: - mlen_pc: t.CSizeT = string.strlen(cls_sha1_pc) + string.strlen(lookup_name) + 2 - mangled_pc: str = pool.alloc(mlen_pc) - if mangled_pc is not None: - viperlib.snprintf(mangled_pc, mlen_pc, "%s.%s", cls_sha1_pc, lookup_name) - call_name = mangled_pc - - # 确定返回类型 - 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: - sp_ty1: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name) - if sp_ty1 is not None: - call_ret_ty = sp_ty1 - else: - cls_sha1_rt: str = HandlesStruct.get_struct_sha1(class_name) - looked_up_ty: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( - pool, cls_sha1_rt, class_name, method_name) - if looked_up_ty is not None: - call_ret_ty = looked_up_ty - else: - # 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单) - vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( - pool, cls_sha1_rt, class_name, method_name) - if vpi_ret_ty is not None: - call_ret_ty = vpi_ret_ty - else: - # Phase A 依赖未就绪(cls_sha1_rt None / 定义模块 text.ll 未生成): - # 标记 pending 下遍重译(对齐 _translate_method_call L4783-4790), - # 绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。 - if cls_sha1_rt is None \ - or self._dep_text_ll_exists(pool, cls_sha1_rt) == 0: - if trans is not None: - trans._deps_pending = 1 - call_ret_ty = llvmlite.Void(pool) - else: - call_ret_ty = self._fail_method_ret_ty(method_name) - - # 参数类型对齐:按目标函数声明的参数类型转换实参(与 _translate_method_call - # 一致)。例如 from_long(10) 的 i32 字面量 → i64 形参(v: t.CLong), - # 不转换则 call(i32) 与 declare(i64) 不匹配,llc 报参数类型错误。 - # 目标函数优先用已找到的 found_func,否则按 mangled 调用名查模块 declare。 - tgt_func_pc: llvmlite.Function | t.CPtr = found_func - if tgt_func_pc is None: - tgt_func_pc = self.find_func_in_module(mod, call_name) - if tgt_func_pc is not None: - prev_pc: llvmlite.Value | t.CPtr = None - cur_arg_pc: llvmlite.Value | t.CPtr = call_head - cur_param_pc: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(tgt_func_pc) - while cur_arg_pc is not None and cur_param_pc is not None: - param_ty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_pc) - if param_ty_pc is not None and cur_arg_pc.Ty is not None: - coerced_pc: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, cur_arg_pc, param_ty_pc) - if coerced_pc is not None and coerced_pc != cur_arg_pc: - # 保持链表完整性:新 Value 继承原节点的 Next,前驱指向新节点 - llvmlite.value_set_next(coerced_pc, cur_arg_pc.Next) - if prev_pc is None: - call_head = coerced_pc - else: - llvmlite.value_set_next(prev_pc, coerced_pc) - cur_arg_pc = coerced_pc - prev_pc = cur_arg_pc - cur_arg_pc = cur_arg_pc.Next - cur_param_pc = llvmlite.param_get_next(cur_param_pc) - - # 确保 declare 存在,然后调用 - self._ensure_method_declare(pool, mod, call_name, call_ret_ty, call_head, call_count) - return llvmlite.build_call(builder, call_name, call_head, call_count, call_ret_ty, 0) - - # ============================================================ - # _resolve_obj_class_name — 解析对象表达式的类名(短名) - # - # 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"), - # 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。 - # 供属性访问/赋值/删除识别 property 时使用。 - # ============================================================ - - # ============================================================ - # _resolve_obj_class_name — 解析对象表达式的类名(短名) - # - # 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"), - # 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。 - # 供属性访问/赋值/删除识别 property 时使用。 - # ============================================================ - def _resolve_obj_class_name(self, pool: memhub.MemBuddy | t.CPtr, - trans: HT.Translator | t.CPtr, - obj_node: ast.AST | t.CPtr) -> str: - """解析对象表达式的类名(短名),失败返回 None""" - if pool is None or trans is None or obj_node is None: - return None - if obj_node.kind() == ast.ASTKind.Name: - obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(obj_node) - if obj_nm.id is not None: - var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, obj_nm.id) - if var_entry is not None and var_entry.AnnotClassName is not None: - annot_val: str = var_entry.AnnotClassName - dot_ptr: str = string.strrchr(annot_val, '.') - if dot_ptr is not None: - return dot_ptr + 1 - return annot_val - return None - - # ============================================================ - # _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用 - # - # 检查 obj 的类是否有 @property/@x.getter 的 attr 方法; - # 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。 - # ============================================================ - - # ============================================================ - # _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用 - # - # 检查 obj 的类是否有 @property/@x.getter 的 attr 方法; - # 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。 - # ============================================================ - def _try_property_getter_attr(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - at_node: ast.Attribute | t.CPtr, - obj_ptr: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr, - fallback_class_name: str = None) -> llvmlite.Value | t.CPtr: - """尝试 property getter 属性访问,返回调用结果 Value;非 getter 返回 None - - fallback_class_name: 对象表达式非 Name 时从 LLVM 类型解析出的类名兜底。 - """ - if at_node is None or at_node.attr is None or obj_ptr is None or trans is None: - return None - class_name: str = self._resolve_obj_class_name(pool, trans, at_node.value) - if class_name is None: - class_name = fallback_class_name - if class_name is None: - return None - meta: int = HandlesClassDef.lookup_method_meta(class_name, at_node.attr) - if meta & HandlesClassDef.META_PROP_GETTER == 0: - return None - # 单参数调用: obj → getter - llvmlite.value_set_next(obj_ptr, None) - return self._translate_property_call( - pool, builder, mod, class_name, at_node.attr, obj_ptr, 1, trans) - - # ============================================================ - # _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用 - # - # 检查 obj 的类是否有 @x.setter 的 attr 方法; - # 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。 - # ============================================================ - - # ============================================================ - # _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用 - # - # 检查 obj 的类是否有 @x.setter 的 attr 方法; - # 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。 - # ============================================================ - def _try_property_setter(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - target_attr: ast.Attribute | t.CPtr, - rhs_val: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr) -> int: - """尝试 property setter 赋值,返回 1=已处理(生成调用)""" - if pool is None or builder is None or mod is None or trans is None: - return 0 - if target_attr is None or target_attr.attr is None or rhs_val is None: - return 0 - class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value) - if class_name is None: - return 0 - meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr) - if meta & HandlesClassDef.META_PROP_SETTER == 0: - return 0 - # 翻译对象值(self 参数) - obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, target_attr.value, None, 0, trans) - if obj_val is None: - return 0 - # 构建参数链表: obj → rhs - llvmlite.value_set_next(obj_val, None) - llvmlite.value_set_next(rhs_val, None) - llvmlite.value_set_next(obj_val, rhs_val) - # setter 函数名带 $set 后缀 - setter_name_buf: str = pool.alloc(128) - if setter_name_buf is None: - return 0 - viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr) - self._translate_property_call(pool, builder, mod, class_name, - setter_name_buf, obj_val, 2, trans) - return 1 - - # ============================================================ - # _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用 - # - # 检查 obj 的类是否有 @x.deleter 的 attr 方法; - # 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。 - # ============================================================ - - # ============================================================ - # _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用 - # - # 检查 obj 的类是否有 @x.deleter 的 attr 方法; - # 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。 - # ============================================================ - def _try_property_deleter(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - target_attr: ast.Attribute | t.CPtr, - trans: HT.Translator | t.CPtr) -> int: - """尝试 property deleter 删除,返回 1=已处理(生成调用)""" - if pool is None or builder is None or mod is None or trans is None: - return 0 - if target_attr is None or target_attr.attr is None: - return 0 - class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value) - if class_name is None: - return 0 - meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr) - if meta & HandlesClassDef.META_PROP_DELETER == 0: - return 0 - # 翻译对象值(self 参数) - obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, target_attr.value, None, 0, trans) - if obj_val is None: - return 0 - llvmlite.value_set_next(obj_val, None) - # deleter 函数名带 $del 后缀 - del_name_buf: str = pool.alloc(128) - if del_name_buf is None: - return 0 - viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr) - self._translate_property_call(pool, builder, mod, class_name, - del_name_buf, obj_val, 1, trans) - return 1 - - # ============================================================ - # _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用 - # - # @staticmethod: 直接 call Class.method(args...),无 self - # @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致) - # ============================================================ - - # ============================================================ - # _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用 - # - # @staticmethod: 直接 call Class.method(args...),无 self - # @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致) - # ============================================================ - def _translate_static_class_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - class_name: str, - method_name: str, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """翻译类名静态/类方法调用,返回 call 结果 Value;非静态/类方法返回 None""" - if pool is None or builder is None or mod is None or trans is None: - return None - if class_name is None or method_name is None or cl is None: - return None - meta: int = HandlesClassDef.lookup_method_meta(class_name, method_name) - is_static: int = 0 - is_class: int = 0 - if meta & HandlesClassDef.META_STATIC != 0: - is_static = 1 - if meta & HandlesClassDef.META_CLASS != 0: - is_class = 1 - if is_static == 0 and is_class == 0: - return None - - # 构建参数链表 - head: llvmlite.Value | t.CPtr = None - total_count: int = 0 - - # @classmethod: 插入栈上分配的类实例指针作为 cls 参数 - if is_class != 0: - struct_ty_cc: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name) - if struct_ty_cc is None: - return None - cls_ptr: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty_cc) - if cls_ptr is None: - return None - llvmlite.value_set_next(cls_ptr, None) - head = cls_ptr - total_count = 1 - - # 翻译调用参数 - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - can: t.CSizeT = 0 - if cargs is not None: - can = len(cargs) - tail: llvmlite.Value | t.CPtr = head - for ai in range(can): - arg_node: ast.AST | t.CPtr = cargs.get(ai) - if arg_node is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node, None, 0, trans) - if arg_val is None: - continue - llvmlite.value_set_next(arg_val, None) - if head is None: - head = arg_val - tail = arg_val - else: - llvmlite.value_set_next(tail, arg_val) - tail = arg_val - total_count += 1 - - # 零参 @staticmethod(如 PyListObj.new()):head 保持 None 是合法的 - # 无参调用,照常走 _translate_property_call(SHA1 前缀名 + 精确返回类型)。 - # 若此处 return None,调用方回退通用路径把方法名当裸函数解析,生成 - # call i32 @new() → 链接 undefined reference(CPythonTest 根因)。 - # @classmethod 恒有 cls_ptr(head 非 None),不受影响。 - return self._translate_property_call(pool, builder, mod, class_name, - method_name, head, total_count, trans) - - # ============================================================ - # _is_list_builtin_method - 判断是否是 list 泛型内置容器方法 - # - # list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/ - # __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list - # 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把 - # list 特化 struct(如 list[AST | CPtr])误当普通结构体走 - # _translate_method_call,会查不到 append 返回类型 → fail-fast - # (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。 - # - # 返回: 1=list 内置方法(应落到 list 内置分支),0=普通方法 - # ============================================================ - - # ============================================================ - # _is_list_builtin_method - 判断是否是 list 泛型内置容器方法 - # - # list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/ - # __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list - # 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把 - # list 特化 struct(如 list[AST | CPtr])误当普通结构体走 - # _translate_method_call,会查不到 append 返回类型 → fail-fast - # (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。 - # - # 返回: 1=list 内置方法(应落到 list 内置分支),0=普通方法 - # ============================================================ - def _is_list_builtin_method(self, class_name: str, - method_name: str) -> int: - """判断 (class_name, method_name) 是否是 list 泛型内置方法""" - if class_name is None or method_name is None: - return 0 - # 类名必须以 "list" 开头(list / list[AST | CPtr] 特化名) - if string.strncmp(class_name, "list", 4) != 0: - return 0 - # 方法名必须是 list 内置方法集合 - if string.strcmp(method_name, "append") == 0: return 1 - if string.strcmp(method_name, "get") == 0: return 1 - if string.strcmp(method_name, "set") == 0: return 1 - if string.strcmp(method_name, "pop") == 0: return 1 - if string.strcmp(method_name, "clear") == 0: return 1 - if string.strcmp(method_name, "__iter__") == 0: return 1 - if string.strcmp(method_name, "__len__") == 0: return 1 - if string.strcmp(method_name, "__getitem__") == 0: return 1 - if string.strcmp(method_name, "__setitem__") == 0: return 1 - return 0 - - # ============================================================ - # _translate_fakeduck_call - FakeDuck: str 变量方法调用 → 扩展类 _Type/_str - # - # 对齐 TPC HandlesExprCall.py L2841-2880: - # ClassName 常规解析失败且对象是 char*(i8*)时,遍历扩展类查找 - # {CN}.{method} 函数。对象是 Name 变量且有影子({var}__meta__,fd2 - # 创建)时 self=影子;否则(字符串字面量/匿名 str)在入口创建临时 - # 影子,写 __data__=obj 值、__mbuddy__=NULL 后作 self,避免 - # bitcast i8* → _str* 读取垃圾指针导致 ACCESS_VIOLATION。 - # ============================================================ - - # ============================================================ - # _translate_fakeduck_call - FakeDuck: str 变量方法调用 → 扩展类 _Type/_str - # - # 对齐 TPC HandlesExprCall.py L2841-2880: - # ClassName 常规解析失败且对象是 char*(i8*)时,遍历扩展类查找 - # {CN}.{method} 函数。对象是 Name 变量且有影子({var}__meta__,fd2 - # 创建)时 self=影子;否则(字符串字面量/匿名 str)在入口创建临时 - # 影子,写 __data__=obj 值、__mbuddy__=NULL 后作 self,避免 - # bitcast i8* → _str* 读取垃圾指针导致 ACCESS_VIOLATION。 - # ============================================================ - def _translate_fakeduck_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cls_name: str, - method_name: str, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """FakeDuck: str 变量方法调用解析到扩展类 _Type/_str,返回 call 结果或 None""" - if pool is None or builder is None or cl is None or trans is None: - return None - if method_name is None: - return None - # 仅对 str 类型触发(AnnotClassName == "str",对象是 char*); - # cls_name 为 None(表达式接收者解析失败)时也尝试 - if cls_name is not None and string.strcmp(cls_name, "str") != 0: - return None - if cl.func is None or cl.func.kind() != ast.ASTKind.Attribute: - return None - fd_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if fd_at is None or fd_at.value is None or fd_at.attr is None: - return None - if string.strcmp(fd_at.attr, method_name) != 0: - return None - # 候选扩展类:先 _Type(a.type_id())后 _str(a.upper() 等) - fd_func: llvmlite.Function | t.CPtr = None - fd_cls: str = None - fd_key: str = pool.alloc(160) - if fd_key is not None: - for fd_ci in range(2): - fd_cn: str = "_Type" - if fd_ci == 1: - fd_cn = "_str" - viperlib.snprintf(fd_key, 160, "%s.%s", fd_cn, method_name) - fd_func = self.find_func_in_module(mod, fd_key) - if fd_func is not None: - fd_cls = fd_cn - break - if fd_func is None or fd_cls is None: - return None - # 扩展类结构体必须已注册(GEP/临时影子需要类型) - fd_sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(fd_cls) - if fd_sty is None: - return None - # 扩展类字段数:有字段(_str)时 self 用影子结构体指针; - # 无字段(_Type)时 self 用对象值 bitcast 到扩展类指针(对齐 TPC L2856-2876) - fd_entry_fd: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(fd_sty) - fd_has_fields: int = 0 - if fd_entry_fd is not None and fd_entry_fd.FieldCount > 0: - fd_has_fields = 1 - # self 参数:优先使用已有影子 {var}__meta__(fd2 创建,仅当扩展类有字段时) - fd_self: llvmlite.Value | t.CPtr = None - if fd_at.value.kind() == ast.ASTKind.Name: - fd_onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fd_at.value) - if fd_onm.id is not None: - # pool 持久缓冲(f-string 栈缓冲在函数返回后失效) - fd_mn: str = pool.alloc(256) - if fd_mn is not None: - viperlib.snprintf(fd_mn, 256, "%s__meta__", fd_onm.id) - fd_meta: llvmlite.Value | t.CPtr = HandlesVar.lookup_current( - trans.SymTab, fd_mn) - if fd_meta is not None and fd_has_fields != 0: - fd_self = fd_meta - if fd_self is None: - if fd_has_fields != 0: - # 有字段扩展类且无影子(字符串字面量等):入口创建临时影子并初始化 - # 先确保 _str 完整定义(跨模块结构体默认 opaque,alloca 报 unsized) - HandlesStruct.ensure_struct_def_in_module(pool, mod, fd_sty) - fd_self = HandlesVar._alloca_at_entry(builder, fd_sty) - if fd_self is None: - return None - fd_obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fd_at.value, None, 0, trans) - if fd_obj_val is not None: - fd_dfe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct.lookup_field(fd_sty, "__data__") - if fd_dfe is not None and fd_dfe.Ty is not None: - fd_dp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, fd_sty, fd_dfe.Ty, fd_self, fd_dfe.Index) - if fd_dp is not None: - llvmlite.build_store(builder, fd_obj_val, fd_dp) - fd_bfe: HandlesStruct.FieldEntry | t.CPtr = \ - HandlesStruct.lookup_field(fd_sty, "__mbuddy__") - if fd_bfe is not None and fd_bfe.Ty is not None: - fd_bp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, fd_sty, fd_bfe.Ty, fd_self, fd_bfe.Index) - fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, fd_bfe.Ty, "null") - if fd_bp is not None and fd_null is not None: - llvmlite.build_store(builder, fd_null, fd_bp) - # FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__) - self._inject_requires_fields( - trans, pool, builder, mod, fd_self, fd_cls) - else: - # 无字段扩展类(_Type):对象值 bitcast 到扩展类指针 - fd_obj_v: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fd_at.value, None, 0, trans) - if fd_obj_v is None: - return None - fd_self = llvmlite.build_bitcast( - builder, fd_obj_v, llvmlite.Ptr(pool, fd_sty)) - if fd_self is None: - return None - # 构建参数链表: self → 其余参数 - llvmlite.value_set_next(fd_self, None) - fd_head: llvmlite.Value | t.CPtr = fd_self - fd_tail: llvmlite.Value | t.CPtr = fd_self - fd_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args - fd_can: int = 0 - if fd_args is not None: - fd_can = len(fd_args) - for fd_ai in range(fd_can): - fd_arg: ast.AST | t.CPtr = fd_args.get(fd_ai) - if fd_arg is not None: - fd_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, fd_arg, None, 0, trans) - # char 常量参数 → 单字符字符串(char 隐式转 str, - # 如 s1.split(','):',' 是 i32 值 44,传给 str 参数须先字符串化, - # 否则运行时 strlen/strncmp 解引用 44 崩溃) - if fd_arg.kind() == ast.ASTKind.Constant: - fd_ac: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(fd_arg) - if fd_ac.const_kind == ast.CONST_CHAR: - ch_buf: str = pool.alloc(2) - if ch_buf is not None: - ch_buf[0] = t.CChar(fd_ac.int_val) - ch_buf[1] = '\0' - fd_av = HandlesExpr.create_global_string( - builder, pool, mod, ch_buf, trans) - if fd_av is not None: - llvmlite.value_set_next(fd_av, None) - llvmlite.value_set_next(fd_tail, fd_av) - fd_tail = fd_av - # 返回类型与调用名(来自 find_func_in_module 命中的函数定义) - fd_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fd_func) - if fd_ret_ty is None: - fd_ret_ty = llvmlite.Int32(pool) - fd_fname: str = llvmlite.function_get_name(fd_func) - if fd_fname is None: - return None - # 返回类型精确化:跨模块 declare 的 list[T] 特化返回类型可能被简化 - # 为 Ptr(i8),调用方变量 alloca 类型随之退化 → parts[0] 走字符下标 - # 路径而非 list 内联 __getitem__(printf %s 解引用字符值崩溃)。 - # 从定义模块 text.ll 读取精确返回类型(对齐普通方法调用 _translate_method_call)。 - fd_sha1: str = pool.alloc(17) - if fd_sha1 is not None: - string.strncpy(fd_sha1, fd_fname, 16) - fd_sha1[16] = '\0' - fd_exact: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( - pool, fd_sha1, fd_cls, method_name) - if fd_exact is not None: - fd_ret_ty = fd_exact - fd_total: int = 1 + fd_can - return llvmlite.build_call(builder, fd_fname, fd_head, fd_total, fd_ret_ty, 0) - - # ============================================================ - # _inject_requires_fields - FakeDuck: with 上下文注入 requires 字段 - # - # 对齐 TPC HandlesExprCall.py L4021-4079: - # 对类 __requires__ 元数据(fd1 注册)中的每个字段,运行时调用 - # _find_provider(field) 查找 with 上下文提供的指针;非 NULL 时 - # bitcast 到字段类型写入 meta_ptr 对应槽位(条件注入,避免覆盖 - # 用户已手动设置的值)。_find_provider 未注册(未 import - # _withcontent)时跳过注入,不影响非 with 场景。 - # ============================================================ - - # ============================================================ - # _inject_requires_fields - FakeDuck: with 上下文注入 requires 字段 - # - # 对齐 TPC HandlesExprCall.py L4021-4079: - # 对类 __requires__ 元数据(fd1 注册)中的每个字段,运行时调用 - # _find_provider(field) 查找 with 上下文提供的指针;非 NULL 时 - # bitcast 到字段类型写入 meta_ptr 对应槽位(条件注入,避免覆盖 - # 用户已手动设置的值)。_find_provider 未注册(未 import - # _withcontent)时跳过注入,不影响非 with 场景。 - # ============================================================ - def _inject_requires_fields(self, trans: HT.Translator | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - meta_ptr: llvmlite.Value | t.CPtr, - class_name: str) -> int: - """在 with 上下文注入 requires 字段,返回注入字段数""" - if trans is None or pool is None or builder is None or mod is None: - return 0 - if meta_ptr is None or class_name is None: - return 0 - # _withcontent._find_provider(跨模块):仅当本模块可见(_withcontent - # 被 import,vpi stub declare 已注入)时才注入。对齐 TPC L4048-4050 - # (Gen.functions.get('_find_provider') 不存在则跳过)——否则非 with - # 项目(如 HashTableTest 未 import _withcontent)也会为每个 _str(...) - # 构造发射 {sha1}._find_provider 调用 → ld.lld undefined symbol。 - fd_fn_probe: llvmlite.Function | t.CPtr = self.find_func_in_module( - mod, "_find_provider") - if fd_fn_probe is None: - return 0 - fd_fname: str = llvmlite.function_get_name(fd_fn_probe) - if fd_fname is None: - return 0 - cnt: int = HandlesType.class_meta_count( - HandlesType.CLASS_META_REQUIRES, class_name) - if cnt <= 0: - return 0 - sty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name) - if sty is None: - return 0 - i8_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if i8_ty_j is None: - return 0 - i8_ptr_ty_j: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_j) - if i8_ptr_ty_j is None: - return 0 - cur_func: llvmlite.Function | t.CPtr = trans._cur_func - if cur_func is None: - return 0 - injected: int = 0 - for ji in range(cnt): - fname: str = HandlesType.class_meta_field_at( - HandlesType.CLASS_META_REQUIRES, class_name, ji) - if fname is None: - continue - fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - sty, fname) - if fe is None or fe.Ty is None: - continue - # 参数:字段名字符串(i8*) - fd_fstr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( - builder, pool, mod, fname, trans) - if fd_fstr is None: - continue - llvmlite.value_set_next(fd_fstr, None) - self._ensure_method_declare( - pool, mod, fd_fname, i8_ptr_ty_j, fd_fstr, 1) - fd_ptr: llvmlite.Value | t.CPtr = llvmlite.build_call( - builder, fd_fname, fd_fstr, 1, i8_ptr_ty_j, 0) - if fd_ptr is None: - continue - # 条件注入:ptr != NULL 才写入(保留用户手动设置的值) - fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, i8_ptr_ty_j, "null") - if fd_null is None: - continue - fd_cmp: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, fd_ptr, fd_null) - if fd_cmp is None: - continue - # 块名唯一化(create_block 不自动编号,同名 label 在文本 IR 中 - # 冲突 → llc "Terminator found in the middle of a basic block") - vtc2: int = trans._label_counter - trans._label_counter = vtc2 + 1 - fd_bb_buf2: str = pool.alloc(64) - if fd_bb_buf2 is None: - continue - viperlib.snprintf(fd_bb_buf2, 64, "fd.skip.%d", vtc2) - fd_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, cur_func, fd_bb_buf2) - viperlib.snprintf(fd_bb_buf2, 64, "fd.inject.%d", vtc2) - fd_inject_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, cur_func, fd_bb_buf2) - if fd_skip_bb is None or fd_inject_bb is None: - continue - llvmlite.build_cond_br(builder, fd_cmp, fd_inject_bb, fd_skip_bb) - # inject 块:bitcast + GEP + store,跳回 skip - llvmlite.position_at_end(builder, fd_inject_bb) - fd_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, fd_ptr, fe.Ty) - if fd_cast is not None: - fd_fp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, sty, fe.Ty, meta_ptr, fe.Index) - if fd_fp is not None: - llvmlite.build_store(builder, fd_cast, fd_fp) - llvmlite.build_br(builder, fd_skip_bb) - # skip 块:恢复 CurBlock,继续后续代码生成 - llvmlite.position_at_end(builder, fd_skip_bb) - injected += 1 - return injected - - # ============================================================ - # _emit_provider_push / _emit_provider_pop - FakeDuck: with 上下文 - # provider push/pop(__provides__ 元数据,fd1 注册) - # - # 对齐 TPC HandlesWith.py L138-174: - # with 进入时对每个提供字段生成 _push_provider(field_str, ctx_i8); - # 退出时生成等量 _pop_provider()。运行时 _withcontent 模块负责 - # 维护 TLS provider 栈,供 _inject_requires_fields 查找。 - # ============================================================ - - # ============================================================ - # _emit_provider_push / _emit_provider_pop - FakeDuck: with 上下文 - # provider push/pop(__provides__ 元数据,fd1 注册) - # - # 对齐 TPC HandlesWith.py L138-174: - # with 进入时对每个提供字段生成 _push_provider(field_str, ctx_i8); - # 退出时生成等量 _pop_provider()。运行时 _withcontent 模块负责 - # 维护 TLS provider 栈,供 _inject_requires_fields 查找。 - # ============================================================ - def _emit_provider_push(self, trans: HT.Translator | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cls_name: str, - ctx_val: llvmlite.Value | t.CPtr) -> int: - """生成 _push_provider(field, ctx_i8) 调用(每提供字段一次),返回字段数""" - if trans is None or pool is None or builder is None or mod is None: - return 0 - if cls_name is None or ctx_val is None: - return 0 - fd_pc: int = HandlesType.class_meta_count( - HandlesType.CLASS_META_PROVIDES, cls_name) - if fd_pc <= 0: - return 0 - # _withcontent._push_provider(跨模块,同 _find_provider 的可见性守卫: - # 本模块未 import _withcontent 时跳过,避免 undefined symbol) - fd_pfn_probe: llvmlite.Function | t.CPtr = self.find_func_in_module( - mod, "_push_provider") - if fd_pfn_probe is None: - return 0 - fd_pfn: str = llvmlite.function_get_name(fd_pfn_probe) - if fd_pfn is None: - return 0 - i8_ty_p: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if i8_ty_p is None: - return 0 - i8_ptr_ty_p: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_p) - if i8_ptr_ty_p is None: - return 0 - ret_i32_p: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if ret_i32_p is None: - return 0 - # ctx 值 bitcast 到 i8*(provider 栈存 void*) - fd_ctx_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, ctx_val, i8_ptr_ty_p) - if fd_ctx_i8 is None: - return 0 - for pi in range(fd_pc): - fname: str = HandlesType.class_meta_field_at( - HandlesType.CLASS_META_PROVIDES, cls_name, pi) - if fname is None: - continue - fd_fstr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string( - builder, pool, mod, fname, trans) - if fd_fstr is None: - continue - llvmlite.value_set_next(fd_fstr, fd_ctx_i8) - llvmlite.value_set_next(fd_ctx_i8, None) - self._ensure_method_declare( - pool, mod, fd_pfn, ret_i32_p, fd_fstr, 2) - llvmlite.build_call(builder, fd_pfn, fd_fstr, 2, ret_i32_p, 0) - return fd_pc - - - def _emit_provider_pop(self, trans: HT.Translator | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cls_name: str) -> int: - """生成 _pop_provider() 调用(每提供字段一次),返回字段数""" - if trans is None or pool is None or builder is None or mod is None: - return 0 - if cls_name is None: - return 0 - fd_pc: int = HandlesType.class_meta_count( - HandlesType.CLASS_META_PROVIDES, cls_name) - if fd_pc <= 0: - return 0 - # _withcontent._pop_provider(跨模块,同 _find_provider 的可见性守卫: - # 本模块未 import _withcontent 时跳过,避免 undefined symbol) - fd_pon_probe: llvmlite.Function | t.CPtr = self.find_func_in_module( - mod, "_pop_provider") - if fd_pon_probe is None: - return 0 - fd_pon: str = llvmlite.function_get_name(fd_pon_probe) - if fd_pon is None: - return 0 - ret_i32_q: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if ret_i32_q is None: - return 0 - self._ensure_method_declare(pool, mod, fd_pon, ret_i32_q, None, 0) - for _pi in range(fd_pc): - llvmlite.build_call(builder, fd_pon, None, 0, ret_i32_q, 0) - return fd_pc - - # ============================================================ - # _write_vtable_slot / _write_vtable_attr — vtable 方法槽位直接写入 - # - # serial0_file.open = serial0_open(devfs 驱动注册模式):把模块级函数 - # 指针写入对象 vtable 的方法槽位。vtable 方法不是数据字段(FieldEntry), - # get_attribute_ptr 查不到 → 此前 fatal_error "属性写入失败"。 - # 对齐 TPC HandlesAssign.py L905-949 的写时复制: - # 对象 vtable 仍指向类默认 vtable 时,先复制一份(internal 全局 + - # llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store - # 函数指针(i8*)。多次写入互不覆盖(第二次起 vtable 已非默认, - # 跳过复制直接写槽位)。 - # ============================================================ - - # ============================================================ - # _write_vtable_slot / _write_vtable_attr — vtable 方法槽位直接写入 - # - # serial0_file.open = serial0_open(devfs 驱动注册模式):把模块级函数 - # 指针写入对象 vtable 的方法槽位。vtable 方法不是数据字段(FieldEntry), - # get_attribute_ptr 查不到 → 此前 fatal_error "属性写入失败"。 - # 对齐 TPC HandlesAssign.py L905-949 的写时复制: - # 对象 vtable 仍指向类默认 vtable 时,先复制一份(internal 全局 + - # llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store - # 函数指针(i8*)。多次写入互不覆盖(第二次起 vtable 已非默认, - # 跳过复制直接写槽位)。 - # ============================================================ - def _write_vtable_slot(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - obj_ptr: llvmlite.Value | t.CPtr, - class_name: str, - method_index: int, - func_val: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr) -> int: - """生成 vtable 槽位写入(写时复制),成功返回 1""" - if pool is None or builder is None or mod is None or trans is None: - return 0 - if obj_ptr is None or class_name is None or func_val is None: - return 0 - if method_index < 0 or trans._cur_func is None: - return 0 - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - if i8_ty is None: - return 0 - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - if i8_ptr_ty is None: - return 0 - i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) - if i8_ptr_ptr_ty is None: - return 0 - method_count: int = HandlesStruct.get_vtable_method_count(class_name) - if method_count <= 0: - return 0 - # 构造 vtable 类型 { i8*, i8*, ... } - 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 0 - # 对象 vtable 槽位(对象头 → i8**,vtable 指针总是第一个字段) - vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, obj_ptr, i8_ptr_ptr_ty) - if vtable_slot is None: - return 0 - vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty, vtable_slot) - if vtable_ptr is None: - return 0 - # 类默认 vtable 地址(比较用) - class_vt: llvmlite.Value | t.CPtr = HandlesExprCall._make_vtable_ref_i8( - pool, builder, mod, class_name, trans) - if class_vt is None: - return 0 - cmp_vt: llvmlite.Value | t.CPtr = llvmlite.build_icmp( - builder, llvmlite.ICMP_EQ, vtable_ptr, class_vt) - if cmp_vt is None: - return 0 - # 块名唯一化(create_block 不自动编号;同函数多次 vtable 写入(如 - # devfs open/close/read/write 连续赋值)同名 label 冲突) - vtc3: int = trans._label_counter - trans._label_counter = vtc3 + 1 - vt_bb_buf3: str = pool.alloc(64) - if vt_bb_buf3 is None: - return 0 - viperlib.snprintf(vt_bb_buf3, 64, "vt.copy.%d", vtc3) - vt_copy_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, trans._cur_func, vt_bb_buf3) - viperlib.snprintf(vt_bb_buf3, 64, "vt.skip.%d", vtc3) - vt_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( - pool, trans._cur_func, vt_bb_buf3) - if vt_copy_bb is None or vt_skip_bb is None: - return 0 - llvmlite.build_cond_br(builder, cmp_vt, vt_copy_bb, vt_skip_bb) - # copy 块:创建 internal 副本全局(zeroinit)+ memcpy + 对象指向副本 - llvmlite.position_at_end(builder, vt_copy_bb) - vtc: int = trans._label_counter - trans._label_counter = vtc + 1 - vcopy_buf: str = pool.alloc(256) - if vcopy_buf is not None: - viperlib.snprintf(vcopy_buf, 256, "%s.vtable.copy.%d", class_name, vtc) - vcopy_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( - pool, vcopy_buf, vtable_ty) - if vcopy_gv is not None: - llvmlite.module_add_global(mod, vcopy_gv) - vcopy_gv.Linkage = None - vcopy_gv.Initializer = "zeroinitializer" - vcopy_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( - pool, llvmlite.Ptr(pool, vtable_ty), vcopy_buf) - if vcopy_ref is not None: - vcopy_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, vcopy_ref, i8_ptr_ty) - if vcopy_i8 is not None: - vt_size: llvmlite.Value | t.CPtr = llvmlite.ConstInt( - pool, llvmlite.Int64(pool), method_count * 8, "vtsz") - if vt_size is not None: - self._emit_llvm_memcpy_intrinsic( - pool, builder, mod, vcopy_i8, class_vt, vt_size) - llvmlite.build_store(builder, vcopy_i8, vtable_slot) - llvmlite.build_br(builder, vt_skip_bb) - # skip 块:reload vtable → GEP 槽位 → store 函数指针(i8*) - llvmlite.position_at_end(builder, vt_skip_bb) - vt_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty, vtable_slot) - if vt_ptr2 is None: - return 0 - vt_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, vt_ptr2, llvmlite.Ptr(pool, vtable_ty)) - if vt_typed is None: - return 0 - vt_slotp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, vtable_ty, i8_ptr_ty, vt_typed, method_index) - if vt_slotp is None: - return 0 - fptr_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, func_val, i8_ptr_ty) - if fptr_i8 is not None: - llvmlite.build_store(builder, fptr_i8, vt_slotp) - return 1 - - - def _write_vtable_attr(self, builder: llvmlite.IRBuilder | t.CPtr, - pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - node: ast.AST | t.CPtr, - rhs_val: llvmlite.Value | t.CPtr, - trans: HT.Translator | t.CPtr) -> int: - """属性写入 obj.method = func:检测 vtable 方法并生成槽位写入(成功返回 1)""" - if node is None or builder is None or pool is None or mod is None: - return 0 - if rhs_val is None or trans is None: - return 0 - at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) - if at is None or at.value is None or at.attr is None: - return 0 - # 解析类名(AnnotClassName;去模块前缀) - class_nm_v: str = None - if at.value.kind() == ast.ASTKind.Name: - nm_v: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) - if nm_v.id is not None: - ve_v: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, nm_v.id) - if ve_v is not None: - class_nm_v = ve_v.AnnotClassName - elif at.value.kind() == ast.ASTKind.Attribute: - # 跨 Mixin:_resolve_attr_field_class 定义在 ExprGenMixin,经 gen 单例调用 - import lib.core.Gen.Generator as Generator - g_vta: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g_vta is not None: - class_nm_v = g_vta._resolve_attr_field_class(pool, trans, at.value) - if class_nm_v is None: - return 0 - fd_dot_v: str = string.strrchr(class_nm_v, '.') - if fd_dot_v is not None: - class_nm_v = fd_dot_v + 1 - if HandlesStruct.get_struct_type(class_nm_v) is None: - return 0 - vm_idx_v: int = HandlesStruct.get_vtable_method_index(class_nm_v, at.attr) - if vm_idx_v < 0: - return 0 - # 解析 obj_ptr(对齐 get_attribute_ptr 前半段:Name 直接查 alloca) - obj_ptr_v: llvmlite.Value | t.CPtr = None - if at.value.kind() == ast.ASTKind.Name: - obj_ptr_v = HandlesVar.lookup_var( - trans.SymTab, ((ast.Name | t.CPtr)(at.value)).id) - else: - obj_ptr_v = HandlesExpr.translate_value( - builder, pool, mod, at.value, None, 0, trans) - if obj_ptr_v is None or obj_ptr_v.Ty is None: - return 0 - # X|t.CPtr 变量(Ptr(Ptr))load 解引用取对象指针 - match obj_ptr_v.Ty: - case llvmlite.LLVMType.Ptr(inner_v): - match inner_v: - case llvmlite.LLVMType.Ptr(_): - obj_ptr_v = llvmlite.build_load(builder, inner_v, obj_ptr_v) - case _: - pass - case _: - pass - if obj_ptr_v is None: - return 0 - return self._write_vtable_slot( - pool, builder, mod, obj_ptr_v, class_nm_v, vm_idx_v, rhs_val, trans) - - # ============================================================ - # _translate_method_call - 翻译方法调用 obj.method(args) - # - # 生成: call @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...) - # - # obj_ptr 是对象变量的 alloca(Ptr(StructTy)),作为 self 参数传入 - # ============================================================ - - # ============================================================ - # _translate_method_call - 翻译方法调用 obj.method(args) - # - # 生成: call @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: HandlesStruct.StructEntry | t.CPtr = None - mc_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(obj_ptr) - if mc_struct_ty is not None: - mc_entry = HandlesStruct.find_struct_by_type(mc_struct_ty) - if mc_entry is None: - mc_entry = HandlesStruct.find_struct(class_name) - - # 构造方法查找名: 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) - - # 泛型模板类方法:特化函数名带类型参数({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 = HandlesStruct.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 - - # 确定调用名(默认 "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 = HandlesStruct.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 = HandlesStruct.get_struct_sha1(class_name) - if ret_anc_sha1 is None: - # 沿 MRO 找第一个有 SHA1 的类 - mro_s0: t.CSizeT | t.CPtr = HandlesStruct.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 = HandlesStruct.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 - spec_name_g: str = HandlesClassDef._specialize_generic_class( - trans, base_buf_g, ta_list_g) - if spec_name_g is not None: - # 特化后重新查找特化函数(特化名 = 调用点类名) - 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 - if gen_done == 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 = HandlesStruct.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 = HandlesStruct.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 = HandlesStruct.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 = HandlesStruct.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 未生成(方法定义模块尚未翻译)→ 标记 - # 重试,保持 void 继续(下遍依赖生成后可精确解析),对齐跨模块 - # 函数路径 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 - call_ret_ty = llvmlite.Void(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 = HandlesStruct.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 = HandlesStruct.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 - call_ret_ty = llvmlite.Void(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 难以定位) - HandlesType.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: - anc_entry_th: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(mc_anc) - 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: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - anc_entry_th, afi_th) - if afe_th is not None: - afn_th: str = HandlesStruct.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: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( - class_name) - if sub_entry_th is not None: - anc_field_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - anc_entry_th.Ty, anc_first_name_th) - sub_field_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.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) - self_arg = llvmlite.build_bitcast(builder, adj_th, anc_ptr_ty_th) - # 构建参数链表: 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: - arg_val_k = HandlesExpr.translate_value( - builder, pool, mod, arg_node_k, None, 0, trans) - 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 = HandlesExpr.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 - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node, None, 0, trans) - 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: - pp: llvmlite.Param | t.CPtr = 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.LLVMType | t.CPtr = llvmlite.param_get_ty(pp) - if pty is not None: - arg_val = HandlesExpr.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 HandlesExpr.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: FuncEntry | t.CPtr = HandlesExprCall.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: FuncDefaultsEntry | t.CPtr = HandlesExprCall.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 - - # 计算需要填充的参数(不含 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 = HandlesExprCall._build_const_from_snapshot( - pool, mod, mdf_gd, mdf_di, trans, builder) - if mdf_val is None: - HandlesType.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 - 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 = HandlesExprCall._check_and_promote_variadic_call( - pool, builder, mod, call_name, head, total_count, cargs, 1, trans) - # try-except:方法含 raise(EH 输出参数)时追加输出实参 + 调用后检测 - return HandlesExprCall._emit_eh_guarded_call( - builder, pool, mod, trans, found_func, call_name, head, total_count, - call_ret_ty, is_variadic_3441) - - # ============================================================ - # _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) - # ============================================================ - - # ============================================================ - # _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: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, "self") - if self_entry is None: - self_entry = HandlesVar.lookup_var_entry(trans.SymTab, "cls") - if self_entry is None: - HandlesType.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError") - return None - cur_class: str = self_entry.AnnotClassName - if cur_class is None: - HandlesType.fatal_error(cl, "super() 只能在类方法内使用(self 无注解类名)") - return None - # 2. 沿 MRO 跳过自身,找第一个定义 method 的祖先类 - anc: str = None - mro_sp: t.CSizeT | t.CPtr = HandlesStruct.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 HandlesExprCall.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) - HandlesType.fatal_error(cl, err_sp, "TypeError") - HandlesType.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: - HandlesType.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: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.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: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry( - anc_entry_sp, afi_sp) - if afe_sp is not None: - afn_sp: str = HandlesStruct.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: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct( - cur_class) - if sub_entry_sp is not None: - anc_field_sp: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - anc_entry_sp.Ty, first_name_sp) - sub_field_sp: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.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) - 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 = HandlesStruct.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 = HandlesFunctions._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 - arg_val_sp: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node_sp, None, 0, trans) - if arg_val_sp is None: - continue - if found_func is not None: - pp_sp: llvmlite.Param | t.CPtr = 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.LLVMType | t.CPtr = llvmlite.param_get_ty(pp_sp) - if pty_sp is not None: - arg_val_sp = HandlesExpr.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 HandlesExpr.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 - ret_ty_sp = llvmlite.Void(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 = HandlesExprCall._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。 - # ============================================================ - - # ============================================================ - # _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: HandlesStruct.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 = HandlesClassDef._get_type_size(fty_fb) - falign_fb: int = HandlesClassDef._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 = HandlesClassDef._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") - # 跳过 % 前缀后逐字符比较 - # ============================================================ - - # ============================================================ - # _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 - - # ============================================================ - # _translate_struct_ctor_kw — 结构体构造函数(关键字参数) - # - # 支持两种语法: - # Point(x=10, y=20) — 全关键字 - # Point(10, y=20) — 混合(位置 + 关键字) - # - # 位置参数按字段索引赋值,关键字参数按字段名查找赋值 - # ============================================================ - - # ============================================================ - # _translate_struct_ctor_kw — 结构体构造函数(关键字参数) - # - # 支持两种语法: - # Point(x=10, y=20) — 全关键字 - # Point(10, y=20) — 混合(位置 + 关键字) - # - # 位置参数按字段索引赋值,关键字参数按字段名查找赋值 - # ============================================================ - def _translate_struct_ctor_kw(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - struct_ty: llvmlite.LLVMType | t.CPtr, - class_name: str, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - keywords: list[ast.AST | t.CPtr] | t.CPtr, - kw_count: t.CSizeT, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """结构体构造函数(关键字参数版本)""" - # 创建临时 alloca - # 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) - if tmp is None: - return llvmlite.ConstZero(pool, struct_ty) - # 诊断节点:取第一个构造实参(有行号),供 _call_method_on_ptr 的 - # fatal_error 显示构造调用行号(本函数无 cl 参数,实参节点最接近调用点) - diag_node_ct: ast.AST | t.CPtr = None - if cargs is not None and len(cargs) > 0: - diag_node_ct = cargs.get(0) - - # OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值 - # 用 find_struct_by_type 规避跨模块同名 find_struct 找错 - kw_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty) - is_oop: int = 0 - if kw_entry is not None: - is_oop = kw_entry.IsOOP - - # 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods) - # 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入) - # 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠) - if is_oop == 0 and class_name is not None: - kw_init_lookup: str = pool.alloc(128) - if kw_init_lookup is not None: - viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name) - # 方案1: 检查当前模块的函数声明 - kw_init_found: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, kw_init_lookup) - if kw_init_found is not None: - is_oop = 1 - if kw_entry is not None: - kw_entry.IsOOP = 1 - kw_entry.HasInit = 1 - else: - # 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入) - kw_init_defaults: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(kw_init_lookup) - if kw_init_defaults is not None: - is_oop = 1 - if kw_entry is not None: - kw_entry.IsOOP = 1 - kw_entry.HasInit = 1 - - if is_oop != 0: - self._call_method_on_ptr(pool, builder, mod, class_name, - "__before_init__", tmp, None, 0, trans) - else: - # 普通结构体:store zeroinitializer + 应用默认值 - zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) - llvmlite.build_store(builder, zero, tmp) - self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans) - - # OOP 结构体且有 __init__:调用 __init__ 而非逐字段 store - # 关键字构造调用此前总是逐字段 store,导致 __init__ 方法体不执行 - # (如 self._args = mb.alloc(...) 不执行 → self._args 为 NULL → add_argument 崩溃) - has_init_flag: int = 0 - has_new_flag: int = 0 - if kw_entry is not None: - has_init_flag = kw_entry.HasInit - has_new_flag = kw_entry.HasNew - - # 跨模块 OOP 类: HasInit 可能未设置(_translate_oop_methods 未被调用) - # 但 IsOOP=1 说明类有方法,推断 HasInit=1(__init__ 在目标模块中存在) - # 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法) - if is_oop != 0 and has_init_flag == 0: - has_init_flag = 1 - - if is_oop != 0 and has_init_flag != 0: - # 有 __init__:构建参数数组并调用 __init__ - storage_ptr: llvmlite.Value | t.CPtr = tmp - - # 如果有 __new__,调用 __new__ 获取实际存储指针 - if has_new_flag != 0: - new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if new_arg_vals is not None: - string.memset(new_arg_vals, 0, 8 * 32) - new_arg_count: int = 0 - for nai in range(can): - new_arg_node: ast.AST | t.CPtr = cargs.get(nai) - if new_arg_node is None: - continue - new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, new_arg_node, None, 0, trans) - if new_av is not None: - if new_arg_count < 32: - new_arg_vals[new_arg_count] = t.CSizeT(new_av) - new_arg_count += 1 - # 关键字参数也传递给 __new__ - for nki in range(kw_count): - nkw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(nki)) - if nkw is None or nkw.value is None: - continue - nkw_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, nkw.value, None, 0, trans) - if nkw_av is not None: - if new_arg_count < 32: - new_arg_vals[new_arg_count] = t.CSizeT(nkw_av) - new_arg_count += 1 - new_ptr: llvmlite.Value | t.CPtr = self._call_method_on_ptr( - pool, builder, mod, class_name, - "__new__", tmp, new_arg_vals, new_arg_count, trans, diag_node_ct) - if new_ptr is not None: - storage_ptr = new_ptr - # __new__ 只保证返回"实例存储指针",声明类型通常是 - # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 - # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 - # obj.method(如 parser.add_argument)get_class_name_by_type - # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 - # bitcast 只改类型层视图,运行时零开销(指针位不变)。 - if new_ptr.Ty is not None: - nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) - if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): - nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) - if nw_bc is not None: - storage_ptr = nw_bc - - # 构建 __init__ 参数数组:位置参数按顺序 + 关键字参数追加 - init_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if init_arg_vals is not None: - string.memset(init_arg_vals, 0, 8 * 32) - init_arg_count: int = 0 - # 位置参数 - for ai_init in range(can): - arg_node_init: ast.AST | t.CPtr = cargs.get(ai_init) - if arg_node_init is None: - continue - av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node_init, None, 0, trans) - if av_init is not None: - if init_arg_count < 32: - init_arg_vals[init_arg_count] = t.CSizeT(av_init) - init_arg_count += 1 - # 关键字参数(追加到末尾,按出现顺序) - for ki_init in range(kw_count): - kw_init: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki_init)) - if kw_init is None or kw_init.value is None: - continue - kw_av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, kw_init.value, None, 0, trans) - if kw_av_init is not None: - if init_arg_count < 32: - init_arg_vals[init_arg_count] = t.CSizeT(kw_av_init) - init_arg_count += 1 - - # 调用 __init__(storage_ptr, *args) - self._call_method_on_ptr(pool, builder, mod, class_name, - "__init__", storage_ptr, init_arg_vals, init_arg_count, trans, diag_node_ct) - - # 返回指针 - return storage_ptr - - # 无 __init__(或非 OOP):逐字段 store 参数值 - # 先处理位置参数(按字段索引,覆盖默认值) - for ai in range(can): - arg: ast.AST | t.CPtr = cargs.get(ai) - if arg is None: - continue - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - if arg_val is None: - continue - fe: HandlesStruct.FieldEntry | t.CPtr = None - if kw_entry is not None: - fe = HandlesStruct._get_field_entry(kw_entry, ai) - else: - fe = HandlesStruct.get_field_by_index(class_name, ai) - if fe is None: - # 位置参数越界(字段表无对应项):fail-fast,绝不静默跳过 - HandlesType.fatal_error( - arg, f"结构体 '{class_name}' 位置参数越界(无对应字段)", "TypeError") - continue - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, tmp, fe.Index) - if field_ptr is None: - continue - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg) - llvmlite.build_store(builder, arg_val, field_ptr) - - # 处理关键字参数(按字段名查找) - # SHA1 从 kw_entry 获取(规避跨模块同名 find_struct 找错) - kw_sha1: str = None - if kw_entry is not None: - kw_sha1 = kw_entry.ModuleSha1 - for ki in range(kw_count): - kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) - if kw is None or kw.arg is None or kw.value is None: - continue - fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field_by_class( - class_name, kw.arg, kw_sha1) - if fe is None: - # 关键字字段不存在:fail-fast(AttributeError),绝不静默跳过 - HandlesType.fatal_error( - kw, f"结构体 '{class_name}' 无字段 '{kw.arg}'", "AttributeError") - continue - kw_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, kw.value, None, 0, trans) - if kw_val is None: - continue - field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( - builder, struct_ty, fe.Ty, tmp, fe.Index) - if field_ptr is None: - continue - kw_val = HandlesExpr.coerce_to_type(builder, kw_val, fe.Ty, kw.value) - llvmlite.build_store(builder, kw_val, field_ptr) - - # 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load - return tmp # ============================================================ # _translate_call_with_kwargs — 带关键字参数的函数调用 @@ -3762,7 +594,7 @@ class CallGenMixin(CallGenBase.CallGenBase): kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki)) if kw is None or kw.arg is None or kw.value is None: continue - if self._kwarg_name_matches(kw.arg, param_name) == 1: + if HandlesExprCall._kwarg_name_matches(kw.arg, param_name) == 1: arg_val = HandlesExpr.translate_value( builder, pool, mod, kw.value, None, 0, trans) break @@ -3811,328 +643,10 @@ class CallGenMixin(CallGenBase.CallGenBase): return self._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst1, mc_src1, mc_num1) return llvmlite.build_call(builder, call_name, head, actual_count, call_ret_ty, 0) - # ============================================================ - # _translate_t_type_cast - 翻译 t.XXX(value) 类型转换 - # - # 当 func 是 t.XXX 形式且 XXX 是已知类型名(map_t_type 能映射)时, - # 将 value 转换为目标类型: - # - 指针 → 整数: ptrtoint (如 t.CUInt64T(ptr) → i64) - # - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*) - # - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8) - # - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*) - # - 整数 → 浮点: sitofp (如 t.CDouble(i32_val) → double) - # - 浮点 → 整数: fptosi (如 t.CInt(double_val) → i32) - # - 浮点 → 浮点: fpext/fptrunc (如 t.CFloat(double_val) → float) - # ============================================================ - - # ============================================================ - # _translate_t_type_cast - 翻译 t.XXX(value) 类型转换 - # - # 当 func 是 t.XXX 形式且 XXX 是已知类型名(map_t_type 能映射)时, - # 将 value 转换为目标类型: - # - 指针 → 整数: ptrtoint (如 t.CUInt64T(ptr) → i64) - # - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*) - # - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8) - # - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*) - # - 整数 → 浮点: sitofp (如 t.CDouble(i32_val) → double) - # - 浮点 → 整数: fptosi (如 t.CInt(double_val) → i32) - # - 浮点 → 浮点: fpext/fptrunc (如 t.CFloat(double_val) → float) - # ============================================================ - def _translate_t_type_cast(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - val: llvmlite.Value | t.CPtr, - target_ty: llvmlite.LLVMType | t.CPtr, - target_name: str = None, - src_node: ast.AST | t.CPtr = None, - trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr: - """类型转换:根据参数类型和目标类型选择转换方式 - - 整数 → 整数拓宽时(对齐 TPC _HandleTypeCastLlvm L1723-1737): - 源 i1(bool)→ zext - 目标类型无符号(target_name 命中 CUIntXXT 等)→ zext - 源表达式无符号(t.CUIntXXT(x) 强转 / 无符号注解变量)→ zext - 否则 → sext(有符号整数拓宽保持数值,如 i8 -50 → 0xFFFFFFCE) - """ - if val is None or target_ty is None: - return None - - val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty) - target_bits: int = HandlesExpr.get_llvm_type_bits(target_ty) - val_fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty) - target_fbits: int = HandlesExpr.get_llvm_float_bits(target_ty) - - # 整数 → 整数: trunc/zext/sext - if val_bits != 0 and target_bits != 0: - if val_bits == target_bits: - return val - elif val_bits < target_bits: - if val_bits == 1: - # i1 是布尔值(来自 icmp/fcmp),无符号语义,必须 zext - return llvmlite.build_zext(builder, val, target_ty) - # 目标类型名已知且为有符号 → 按源符号性 sext/zext(对齐 TPC L1723-1737); - # 目标名未知(int()/联合类型强转等)保持默认 zext(旧行为) - need_sext: int = 0 - if target_name is not None and HandlesExpr._type_name_unsigned(target_name) == 0: - if src_node is None or HandlesExpr._node_type_unsigned(pool, src_node, trans) == 0: - need_sext = 1 - if need_sext != 0: - return llvmlite.build_sext(builder, val, target_ty) - return llvmlite.build_zext(builder, val, target_ty) - else: - return llvmlite.build_trunc(builder, val, target_ty) - - # 整数 → 浮点: sitofp - if val_bits != 0 and target_fbits != 0: - return llvmlite.build_si2fp(builder, val, target_ty) - - # 浮点 → 整数: fptosi - if val_fbits != 0 and target_bits != 0: - return llvmlite.build_fp2si(builder, val, target_ty) - - # 浮点 → 浮点: fpext/fptrunc - if val_fbits != 0 and target_fbits != 0: - if val_fbits == target_fbits: - return val - elif val_fbits < target_fbits: - return llvmlite.build_fpext(builder, val, target_ty) - else: - return llvmlite.build_fptrunc(builder, val, target_ty) - - # 指针 → 整数: ptrtoint - if val_bits == 0 and val_fbits == 0 and target_bits != 0: - return llvmlite.build_ptrtoint(builder, val, target_ty) - - # 整数 → 指针: inttoptr(必须排除浮点 target,浮点 target_bits 也是 0) - if val_bits != 0 and target_bits == 0 and target_fbits == 0: - return llvmlite.build_inttoptr(builder, val, target_ty) - - # 指针 → 指针: bitcast - return llvmlite.build_bitcast(builder, val, target_ty) - - # ============================================================ - # 泛型实例化辅助:从 Subscript slice 提取类型实参名 - # ============================================================ - # _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) - # HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 - # ============================================================ - # 泛型实例化辅助:从 Subscript slice 提取类型实参名 - # ============================================================ - # _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute) - # HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用 - - def _extract_type_args_from_slice(self, pool: memhub.MemBuddy | t.CPtr, - slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr: - """从 Subscript.slice 提取类型实参名列表 - - list[int] -> ["int"] - dict[str, int] -> ["str", "int"] - list[AST | t.CPtr] -> ["AST|t.CPtr"] - """ - if slice_node is None or pool is None: - return None - # elem_size=8:str 是 i8* 指针(8 字节),若用 4 则双元素时 append 写 8 字节 - # 但步长按 4 计算,第 2 个元素覆盖第 1 个元素高 4 字节 → get 读出垃圾指针崩溃 - result: list[str] | t.CPtr = list[str](pool, 8) - k: int = slice_node.kind() - if k == ast.ASTKind.Tuple: - tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(slice_node) - elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts - if elts is not None: - n: t.CSizeT = len(elts) - i: t.CSizeT - for i in range(n): - elt: ast.AST | t.CPtr = elts.get(i) - tn: str = HandlesType._get_type_name_from_annotation(pool, elt) - if tn is not None: - result.append(tn) - else: - tn: str = HandlesType._get_type_name_from_annotation(pool, slice_node) - if tn is not None: - result.append(tn) - return result - - # ============================================================ - # 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__ - # - # 复用 translate_list_literal 的构造逻辑: - # 1. alloca tmp(特化类临时空间,作为 __new__ 的 self) - # 2. 翻译 cl.args 为参数指针数组 - # 3. call __new__(tmp, *args) → storage_ptr - # 4. call __before_init__(storage_ptr) - # 5. call __init__(storage_ptr, *args) - # 6. return storage_ptr - # - # 必须独立于 translate_call 的普通函数路径:spec_name 是类名不是函数名, - # 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1 - # 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。 - # ============================================================ - - # ============================================================ - # 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__ - # - # 复用 translate_list_literal 的构造逻辑: - # 1. alloca tmp(特化类临时空间,作为 __new__ 的 self) - # 2. 翻译 cl.args 为参数指针数组 - # 3. call __new__(tmp, *args) → storage_ptr - # 4. call __before_init__(storage_ptr) - # 5. call __init__(storage_ptr, *args) - # 6. return storage_ptr - # - # 必须独立于 translate_call 的普通函数路径:spec_name 是类名不是函数名, - # 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1 - # 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。 - # ============================================================ - def _infer_generic_ctor_type_arg(self, pool: memhub.MemBuddy | t.CPtr, - arg_node: ast.AST | t.CPtr, - class_name: str) -> str: - """从构造实参 AST 推断泛型类型实参名;无法推断时 fail-fast(绝不默认 "int") - - 裸名泛型类构造(Box(42) → Box[int])需要从实参推断类型实参。 - 对应 TPC _HandleGenericClassNewLlvm 的推断逻辑(常量/类型转换调用)。 - 注意:本函数仅做 AST 静态推断,不发射 IR(避免重复翻译实参)。 - """ - if pool is None or arg_node is None: - HandlesType.fatal_error( - None, - f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)", - "TypeError") - return "int" - k: int = arg_node.kind() - # 常量: 42→int, 3.14→double, "abc"→str - if k == ast.ASTKind.Constant: - cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg_node) - if cn.const_kind == ast.CONST_FLOAT: - return "double" - if cn.const_kind == ast.CONST_STR: - return "str" - return "int" - # 类型转换调用: int(...)/float(...)/t.CInt(...)/t.CDouble(...) - if k == ast.ASTKind.Call: - cl_f: ast.Call | t.CPtr = (ast.Call | t.CPtr)(arg_node) - if cl_f.func is not None: - if cl_f.func.kind() == ast.ASTKind.Name: - fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_f.func) - if fn_nm.id is not None: - # 与下方 Attribute 分支的 strstr 匹配一致:from t import CInt - # 后 `CInt(0)` 的 func 是 Name("CInt"),仅精确匹配 int/float - # 会漏判 → fail-fast 误杀(VectorGenericTest 隐式泛型推断)。 - if string.strcmp(fn_nm.id, "float") == 0 or string.strcmp(fn_nm.id, "double") == 0 \ - or string.strstr(fn_nm.id, "Float") is not None or string.strstr(fn_nm.id, "Double") is not None: - return "double" - if string.strcmp(fn_nm.id, "int") == 0 \ - or string.strstr(fn_nm.id, "Int") is not None or string.strstr(fn_nm.id, "UInt") is not None \ - or string.strstr(fn_nm.id, "Char") is not None or string.strstr(fn_nm.id, "Short") is not None \ - or string.strstr(fn_nm.id, "Long") is not None: - return "int" - elif cl_f.func.kind() == ast.ASTKind.Attribute: - fn_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_f.func) - if fn_at.attr is not None: - if string.strstr(fn_at.attr, "Float") is not None or string.strstr(fn_at.attr, "Double") is not None: - return "double" - if string.strstr(fn_at.attr, "Int") is not None or string.strstr(fn_at.attr, "UInt") is not None or string.strstr(fn_at.attr, "Char") is not None or string.strstr(fn_at.attr, "Short") is not None or string.strstr(fn_at.attr, "Long") is not None: - return "int" - # 类型转换调用(Call)但函数名无法识别:明确的类型意图却无法解析, - # fail-fast(区别于普通变量 Name——那是非 T 参数,默认 int 被过滤)。 - HandlesType.fatal_error( - arg_node, - f"无法从实参推断泛型类 '{class_name}' 的类型实参,请显式标注如 {class_name}[类型](...)", - "TypeError") - return "int" - # 非类型转换节点(普通变量 Name/Attribute 等,如 Vector(pool, 8, ...) - # 的 pool 参数):不是 T 类型提示,返回默认 "int"(调用方"过滤纯 int" - # 逻辑将其排除,只保留 float/str 等区分性提示)。 - return "int" - def _translate_generic_ctor_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - spec_name: str, - cl: ast.Call | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__""" - if pool is None or builder is None or mod is None or spec_name is None or cl is None: - return None - - # 查找 struct entry 获取类型 - struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name) - if struct_entry is None: - HandlesType.fatal_error(cl, "泛型类构造调用: 特化类未注册") - return None - struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty - if struct_ty is None: - return None - - # 确保结构体定义在当前模块中可用(供 alloca 分配空间) - HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty) - - # alloca tmp(self 指针) - tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty) - if tmp is None: - return None - - # 翻译 cl.args 为参数指针数组(extra_args[i] = Value 指针) - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - can: t.CSizeT = 0 - if cargs is not None: - can = len(cargs) - - extra_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32) - if extra_args is None: - return None - string.memset(extra_args, 0, 8 * 32) - - ai: t.CSizeT = 0 - while ai < can: - if ai >= 32: - # 定长 8*32 槽:超过 32 个实参继续写会越界污染 pool 相邻块,fail-fast - HandlesType.fatal_error( - cl, "泛型构造实参超过 32 个上限", "TypeError") - break - arg_node: ast.AST | t.CPtr = cargs.get(ai) - if arg_node is not None: - arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg_node, None, 0, trans) - if arg_val is not None: - extra_args[ai] = t.CSizeT(arg_val) - ai += 1 - - # 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针 - # __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用 - # (与 _translate_struct_ctor 保持一致,避免为无 __new__ 的类生成过度声明) - storage_ptr: llvmlite.Value | t.CPtr = tmp - has_new_flag: int = 0 - if struct_entry is not None: - has_new_flag = struct_entry.HasNew - if has_new_flag != 0: - new_ptr: llvmlite.Value | t.CPtr = self._call_method_on_ptr( - pool, builder, mod, spec_name, "__new__", tmp, extra_args, can, trans) - if new_ptr is not None: - storage_ptr = new_ptr - # __new__ 只保证返回"实例存储指针",声明类型通常是 - # `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。 - # 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的 - # obj.method(如 parser.add_argument)get_class_name_by_type - # 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。 - # bitcast 只改类型层视图,运行时零开销(指针位不变)。 - if new_ptr.Ty is not None: - nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty) - if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty): - nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty) - if nw_bc is not None: - storage_ptr = nw_bc - - # call __before_init__(storage_ptr)(TransPyV 自动生成,零值填充) - self._call_method_on_ptr( - pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans) - - # call __init__(storage_ptr, *args) - self._call_method_on_ptr( - pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, can, trans) - - return storage_ptr # ============================================================ # 翻译函数调用 Call(func, args) — 模块级版本 @@ -4165,7 +679,7 @@ class CallGenMixin(CallGenBase.CallGenBase): if sup_cl.func is not None and sup_cl.func.kind() == ast.ASTKind.Name: sup_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sup_cl.func) if sup_nm.id is not None and string.strcmp(sup_nm.id, "super") == 0: - return self._translate_super_call( + return HandlesExprCall._translate_super_call( pool, builder, mod, cl, func_name, trans) # ctraits 宏库编译期谓词:ctraits.isptr(x) 不生成运行时调用, @@ -4199,7 +713,7 @@ class CallGenMixin(CallGenBase.CallGenBase): template_cd: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(gen_class_name) if template_cd is not None: # 提取类型实参 - gen_type_args: list[str] | t.CPtr = self._extract_type_args_from_slice(pool, sub_node.slice) + gen_type_args: list[str] | t.CPtr = HandlesExprCall._extract_type_args_from_slice(pool, sub_node.slice) if gen_type_args is not None and len(gen_type_args) > 0: # 特化泛型类,返回特化类名 spec_name: str = HandlesClassDef._specialize_generic_class( @@ -4208,7 +722,7 @@ class CallGenMixin(CallGenBase.CallGenBase): # 泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__ # 不能直接用 spec_name 作为 func_name(会走裸名调用路径, # 被 star import 回退误导用错误的 SHA1,且缺少 __new__ 方法名后缀) - return self._translate_generic_ctor_call( + return HandlesExprCall._translate_generic_ctor_call( pool, builder, mod, spec_name, cl, trans) else: # 泛型类模板未找到:可能是泛型函数手动传类型参数调用 xxx[T](x) @@ -4237,7 +751,7 @@ class CallGenMixin(CallGenBase.CallGenBase): binop_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, binop_args.get(0), funcs_ptr, func_count, trans) if binop_arg_val is not None: - return self._translate_t_type_cast(pool, builder, binop_arg_val, binop_ty) + return HandlesExprCall._translate_t_type_cast(pool, builder, binop_arg_val, binop_ty) return None # 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR,不生成 call) @@ -4333,7 +847,7 @@ class CallGenMixin(CallGenBase.CallGenBase): builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) if cast_arg is not None: i8_ptr_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - return self._translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin) + return HandlesExprCall._translate_t_type_cast(pool, builder, cast_arg, i8_ptr_ty_builtin) return None elif string.strcmp(cast_fn_name, "int") == 0: # int(x) → i32 @@ -4341,7 +855,7 @@ class CallGenMixin(CallGenBase.CallGenBase): builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) if cast_arg_int is not None: i32_ty_builtin: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - return self._translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin) + return HandlesExprCall._translate_t_type_cast(pool, builder, cast_arg_int, i32_ty_builtin) return None elif string.strcmp(cast_fn_name, "bool") == 0: # bool(x) → i1(严格 != 0 归一化) @@ -4421,7 +935,7 @@ class CallGenMixin(CallGenBase.CallGenBase): tc_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, tc_arg_node, None, 0, trans) if tc_arg_val is not None: - return self._translate_t_type_cast( + return HandlesExprCall._translate_t_type_cast( pool, builder, tc_arg_val, target_ty, func_name, tc_arg_node, trans) # t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL @@ -4457,7 +971,7 @@ class CallGenMixin(CallGenBase.CallGenBase): mt_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) if mt_arg_val is not None: - return self._translate_t_type_cast( + return HandlesExprCall._translate_t_type_cast( pool, builder, mt_arg_val, mod_td_ty, func_name, cargs.get(0), trans) @@ -4525,7 +1039,7 @@ class CallGenMixin(CallGenBase.CallGenBase): bare_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, bare_arg_node, None, 0, trans) if bare_arg_val is not None: - return self._translate_t_type_cast( + return HandlesExprCall._translate_t_type_cast( pool, builder, bare_arg_val, bare_ty, bare_fn_name, bare_arg_node, trans) if bare_ty is not None and can == 1: @@ -4534,7 +1048,7 @@ class CallGenMixin(CallGenBase.CallGenBase): bare_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( builder, pool, mod, bare_arg_node, None, 0, trans) if bare_arg_val is not None: - return self._translate_t_type_cast( + return HandlesExprCall._translate_t_type_cast( pool, builder, bare_arg_val, bare_ty, bare_fn_name, bare_arg_node, trans) @@ -4626,7 +1140,7 @@ class CallGenMixin(CallGenBase.CallGenBase): if sub_sz.value is not None and sub_sz.value.kind() == ast.ASTKind.Name: gen_nm_sz: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_sz.value) if gen_nm_sz.id is not None: - gen_args_sz: list[str] | t.CPtr = self._extract_type_args_from_slice(pool, sub_sz.slice) + gen_args_sz: list[str] | t.CPtr = HandlesExprCall._extract_type_args_from_slice(pool, sub_sz.slice) if gen_args_sz is not None and len(gen_args_sz) > 0: gargs_resolved: list[str] | t.CPtr = list[str](pool, 8) if gargs_resolved is not None: @@ -4768,7 +1282,7 @@ class CallGenMixin(CallGenBase.CallGenBase): len_arg_node, "len() 参数类型推断失败(结构体类名未知)", "TypeError") # list 内置 __len__:读 __count__(GEP 偏移 1,i64) - if self._is_list_builtin_method(len_cls_nm, "__len__") != 0: + if HandlesExprCall._is_list_builtin_method(len_cls_nm, "__len__") != 0: i64_ty_lb: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) idx_one_lb: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) cnt_ptr_lb: llvmlite.Value | t.CPtr = llvmlite.build_gep( @@ -4926,10 +1440,10 @@ class CallGenMixin(CallGenBase.CallGenBase): rc_tag_sc: int = HandlesClassDef._lookup_renum_variant_in_class( st_nm.id, func_name) if rc_tag_sc >= 0: - return self._translate_renum_construct( + return HandlesExprCall._translate_renum_construct( pool, builder, mod, st_nm.id, func_name, rc_tag_sc, cargs, can, trans) - st_res: llvmlite.Value | t.CPtr = self._translate_static_class_call( + st_res: llvmlite.Value | t.CPtr = HandlesExprCall._translate_static_class_call( pool, builder, mod, st_nm.id, func_name, cl, trans) if st_res is not None: return st_res @@ -4961,7 +1475,7 @@ class CallGenMixin(CallGenBase.CallGenBase): builder, pool, mod, cargs.get(ri_im + 1), None, 0, trans) if im_rv is not None: im_rem[ri_im] = t.CSizeT(im_rv) - im_res: llvmlite.Value | t.CPtr = self._call_method_on_ptr( + im_res: llvmlite.Value | t.CPtr = HandlesExprCall._call_method_on_ptr( pool, builder, mod, st_nm.id, func_name, im_self, im_rem, can - 1, trans) if im_res is not None: @@ -4978,7 +1492,7 @@ class CallGenMixin(CallGenBase.CallGenBase): if st_at2.value.kind() == ast.ASTKind.Name: # ClassName 是已注册结构体类名时尝试静态/类方法 if HandlesStruct.get_struct_type(st_at2.attr) is not None: - st_res2: llvmlite.Value | t.CPtr = self._translate_static_class_call( + st_res2: llvmlite.Value | t.CPtr = HandlesExprCall._translate_static_class_call( pool, builder, mod, st_at2.attr, func_name, cl, trans) if st_res2 is not None: return st_res2 @@ -5008,8 +1522,8 @@ class CallGenMixin(CallGenBase.CallGenBase): # _translate_method_call 会查 append 返回类型(函数/text.ll/ # vpi stub 均未命中)→ fail-fast。检测到 list 方法时 # 跳过 method_call,落到内置分支(NewAstTest body.append 根因)。 - if self._is_list_builtin_method(class_nm, func_name) == 0: - return self._translate_method_call( + if HandlesExprCall._is_list_builtin_method(class_nm, func_name) == 0: + return HandlesExprCall._translate_method_call( pool, builder, mod, class_nm, func_name, obj_var, cl, trans) # 指针变量: alloca 类型是 Ptr(Ptr(Struct)) @@ -5020,18 +1534,18 @@ class CallGenMixin(CallGenBase.CallGenBase): pool, inner_struct_ty) if inner_nm is not None: # list 内置方法同样跳过(同 Ptr(Struct) 分支) - if self._is_list_builtin_method(inner_nm, func_name) == 0: + if HandlesExprCall._is_list_builtin_method(inner_nm, func_name) == 0: obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load( builder, obj_struct_ty, obj_var) if obj_ptr is not None: - return self._translate_method_call( + return HandlesExprCall._translate_method_call( pool, builder, mod, inner_nm, func_name, obj_ptr, cl, trans) # FakeDuck: str/bytes 变量(Ptr(i8),AnnotClassName 为空) # 方法调用 → 扩展类 _Type/_str(a.type_id() / a.upper())。 # 前置拦截:常规结构体方法分支全落空时,尝试扩展类方法 # (find_func_in_module 未命中返回 None,不影响正常路径)。 - fd_name_res: llvmlite.Value | t.CPtr = self._translate_fakeduck_call( + fd_name_res: llvmlite.Value | t.CPtr = HandlesExprCall._translate_fakeduck_call( pool, builder, mod, None, func_name, cl, trans) if fd_name_res is not None: return fd_name_res @@ -5058,25 +1572,25 @@ class CallGenMixin(CallGenBase.CallGenBase): if HandlesStruct.get_struct_type(cls_nm2) is not None: # list 内置方法跳过 method_call(同 Ptr(Struct) 分支), # 落到下方 list 内置分支 - if self._is_list_builtin_method(cls_nm2, func_name) == 0: + if HandlesExprCall._is_list_builtin_method(cls_nm2, func_name) == 0: # 结构体已注册:load obj_ptr 走方法调用 i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( pool, llvmlite.Int8(pool)) obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load( builder, i8_ptr_ty2, obj_var) if obj_ptr2 is not None: - return self._translate_method_call( + return HandlesExprCall._translate_method_call( pool, builder, mod, cls_nm2, func_name, obj_ptr2, cl, trans) else: # list 内置方法跳过(结构体未注册路径同样不能 # 构造 {sha1}.{cls}.append 调用名——list 方法无此函数) - if self._is_list_builtin_method(cls_nm2, func_name) == 0: + if HandlesExprCall._is_list_builtin_method(cls_nm2, func_name) == 0: # FakeDuck: str 变量方法调用 → 扩展类 _Type/_str # a.type_id() / a.upper() / " ".isspace() 等 # AnnotClassName=="str" 且对象是 char* 时触发, # self 用影子结构体 {a}__meta__(或临时影子)。 - fd_res: llvmlite.Value | t.CPtr = self._translate_fakeduck_call( + fd_res: llvmlite.Value | t.CPtr = HandlesExprCall._translate_fakeduck_call( pool, builder, mod, cls_nm2, func_name, cl, trans) if fd_res is not None: return fd_res @@ -5215,13 +1729,13 @@ class CallGenMixin(CallGenBase.CallGenBase): builder, pool, mod, expr_method_at.value, trans) if expr_addr is not None: expr_obj = expr_addr - return self._translate_method_call( + return HandlesExprCall._translate_method_call( pool, builder, mod, expr_cls_nm, func_name, expr_obj, cl, trans) # FakeDuck: 表达式接收者解析失败且对象是 char* 时 # (如 " ".isspace()),尝试扩展类 _Type/_str 方法 # (self 用临时影子,对齐 TPC L2858-2873) - fd_expr_res: llvmlite.Value | t.CPtr = self._translate_fakeduck_call( + fd_expr_res: llvmlite.Value | t.CPtr = HandlesExprCall._translate_fakeduck_call( pool, builder, mod, None, func_name, cl, trans) if fd_expr_res is not None: return fd_expr_res @@ -5288,7 +1802,7 @@ class CallGenMixin(CallGenBase.CallGenBase): builder, pool, mod, attr_method_at.value, trans) if field_addr is not None: field_obj = field_addr - return self._translate_method_call( + return HandlesExprCall._translate_method_call( pool, builder, mod, field_cls_nm, func_name, field_obj, cl, trans) @@ -5621,7 +2135,7 @@ class CallGenMixin(CallGenBase.CallGenBase): if gen_ctor_entry is not None: ctor_is_oop = gen_ctor_entry.IsOOP if ctor_is_oop != 0: - return self._translate_struct_ctor( + return HandlesExprCall._translate_struct_ctor( pool, builder, mod, struct_ty, func_name, cargs, 0, trans) # @t.NoVTable 类(无方法、类语义/指针对象):无参构造也应分配内存 # 返回指针。否则按值结构体返回 ConstZero(struct_ty),LHS 联合注解 @@ -5631,7 +2145,7 @@ class CallGenMixin(CallGenBase.CallGenBase): if gen_ctor_entry is not None: ctor_is_novt = gen_ctor_entry.IsNoVTable if ctor_is_novt != 0: - return self._translate_struct_ctor( + return HandlesExprCall._translate_struct_ctor( pool, builder, mod, struct_ty, func_name, cargs, 0, trans) # 普通结构体:检查是否有默认值(用 entry 直接访问) gen_has_defaults: int = 0 @@ -5646,18 +2160,18 @@ class CallGenMixin(CallGenBase.CallGenBase): gen_has_defaults = HandlesStruct.struct_has_defaults(func_name) if gen_has_defaults == 1: # 有默认值:走构造函数路径应用默认值 - return self._translate_struct_ctor( + return HandlesExprCall._translate_struct_ctor( pool, builder, mod, struct_ty, func_name, cargs, 0, trans) # 无默认值:返回 zeroinitializer ret: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty) return ret if kw_count > 0: # 有关键字参数:按字段名赋值 - return self._translate_struct_ctor_kw( + return HandlesExprCall._translate_struct_ctor_kw( pool, builder, mod, struct_ty, func_name, cargs, can, keywords, kw_count, trans) # 仅位置参数:按字段顺序构建 - return self._translate_struct_ctor( + return HandlesExprCall._translate_struct_ctor( pool, builder, mod, struct_ty, func_name, cargs, can, trans) # 裸名泛型类模板构造: Box(42) → 从实参推断类型实参 → 特化 → 构造 @@ -5694,7 +2208,7 @@ class CallGenMixin(CallGenBase.CallGenBase): if hint_bare is not None: hi_bare: t.CSizeT for hi_bare in range(can): - hty_bare: str = self._infer_generic_ctor_type_arg(pool, cargs.get(hi_bare), func_name) + hty_bare: str = HandlesExprCall._infer_generic_ctor_type_arg(pool, cargs.get(hi_bare), func_name) if string.strcmp(hty_bare, "int") != 0: hint_bare.append(hty_bare) tpi_bare: t.CSizeT = 0 @@ -5703,12 +2217,12 @@ class CallGenMixin(CallGenBase.CallGenBase): if tpi_bare < len(hint_bare): ta_bare = hint_bare.get(tpi_bare) elif tpi_bare < can: - ta_bare = self._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare), func_name) + ta_bare = HandlesExprCall._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare), func_name) inferred_args_bare.append(ta_bare) spec_name_bare: str = HandlesClassDef._specialize_generic_class( trans, func_name, inferred_args_bare) if spec_name_bare is not None: - return self._translate_generic_ctor_call( + return HandlesExprCall._translate_generic_ctor_call( pool, builder, mod, spec_name_bare, cl, trans) # REnum 变体构造检测: ClassName.VariantName(args...) @@ -5727,7 +2241,7 @@ class CallGenMixin(CallGenBase.CallGenBase): rc_tag: int = HandlesClassDef._lookup_renum_variant_in_class( rc_cls_name, func_name) if rc_tag >= 0: - return self._translate_renum_construct( + return HandlesExprCall._translate_renum_construct( pool, builder, mod, rc_cls_name, func_name, rc_tag, cargs, can, trans) @@ -6413,311 +2927,17 @@ class CallGenMixin(CallGenBase.CallGenBase): builder, pool, mod, trans, found_func, call_name, head, can, call_ret_ty, is_variadic_call) - # ============================================================ - # _func_has_eh_params - 被调函数签名是否含 try-except EH 输出参数 - # - # EH 参数(%__eh_msg_out__/__eh_code_out__)由 translate_function_def/ - # _translate_method 在含 raise 的函数签名末尾注入(main 除外)。 - # ============================================================ - - def _va_arg_get_alloca_ptr(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - arg_node: ast.AST | t.CPtr, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """获取 va_list 变量的 alloca 指针(不 load) - - va_arg/va_start/va_end 需要的是 va_list 对象的地址(alloca 指针), - 而非 va_list 的值。若 arg_node 是 Name,查符号表获取 alloca; - 否则用 translate_value 翻译(调用者负责确保传入的是指针)。 - """ - if arg_node is None: - return None - # Name 节点:直接查符号表获取 alloca 指针(不 load) - if arg_node.kind() == ast.ASTKind.Name: - nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg_node) - if nm.id is not None: - alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) - if alloca is not None: - return alloca - # 回退:translate_value(可能返回 load 后的值,仅适用于已是指针的情况) - return HandlesExpr.translate_value(builder, pool, mod, arg_node, funcs_ptr, func_count, trans) - def _resolve_va_arg_type(self, pool: memhub.MemBuddy | t.CPtr, - type_node: ast.AST | t.CPtr, - trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: - """解析 va_arg/arg 的类型参数为 LLVMType - - 支持的类型表达式: - t.CInt / t.CInt32T → i32 - t.CInt64T → i64 - t.CDouble → double - t.CPtr / str → i8* - str / bytes → i8* - 无类型参数时默认 i32(vsnprintf 中 va_arg(ap) 常用于读取 i32) - """ - if type_node is None: - return llvmlite.Int32(pool) - # 使用 HandlesType.resolve_annotation_type 解析类型表达式 - resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( - pool, type_node, trans._imported_modules, trans._from_imports, trans) - if resolved is not None: - return resolved - # 类型节点存在但解析失败:fail-fast,绝不回退 i32(会按错宽度读变参槽位) - HandlesType.fatal_error(type_node, "va_arg 类型解析失败", "TypeError") - return llvmlite.Int32(pool) - def _translate_va_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """va_arg(ap, type) / va_arg(ap) → %N = va_arg , - - 生成 LLVM va_arg 指令,从 va_list 读取下一个变长参数。 - """ - if can == 0 or cargs is None: - return llvmlite.const_int32(pool, 0) - - # 第一个参数:va_list(求值为 i8* 地址值,对齐 TPC _HandleVaArgLlvm) - # 当前函数 *args:translate_value 经 vararg 名映射直接返回 va_list 缓冲区地址; - # 转发场景(sprintf → vsnprintf 的 ap 参数):translate_value load 参数得到地址值。 - ap_node: ast.AST | t.CPtr = cargs.get(0) - ap_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, ap_node, None, 0, trans) - if ap_val is None: - return llvmlite.const_int32(pool, 0) - ap_ptr: llvmlite.Value | t.CPtr = ap_val - - # 第二个参数:目标类型(可选,默认 i32) - arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if can >= 2: - type_node: ast.AST | t.CPtr = cargs.get(1) - arg_ty = self._resolve_va_arg_type(pool, type_node, trans) - - # Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(对齐 TPC emit_va_arg L72-73) - read_ty: llvmlite.LLVMType | t.CPtr = arg_ty - abits_va: int = HandlesExpr.get_llvm_type_bits(arg_ty) - if abits_va != 0 and abits_va < 64: - read_ty = llvmlite.Int64(pool) - - # 生成 va_arg 指令 - return llvmlite.build_va_arg(builder, ap_ptr, read_ty) - def _translate_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cl: ast.Call | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """arg(type) → %N = va_arg , - - 使用当前函数的隐式 va_list(trans._va_list_ptr), - 简化 *args 函数体内的 va_arg 调用。 - """ - if trans._va_list_ptr is None: - return llvmlite.const_int32(pool, 0) - - # 第一个参数:目标类型(可选,默认 i32) - arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - if can >= 1 and cargs is not None: - type_node: ast.AST | t.CPtr = cargs.get(0) - arg_ty = self._resolve_va_arg_type(pool, type_node, trans) - - # Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(与 _translate_va_arg_sugar 一致) - read_ty: llvmlite.LLVMType | t.CPtr = arg_ty - abits_arg: int = HandlesExpr.get_llvm_type_bits(arg_ty) - if abits_arg != 0 and abits_arg < 64: - read_ty = llvmlite.Int64(pool) - - # 生成 va_arg 指令(使用 trans._va_list_ptr 作为 va_list 地址) - return llvmlite.build_va_arg(builder, trans._va_list_ptr, read_ty) - def _translate_va_start_sugar(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """va_start(ap, last_arg) → call void @llvm.va_start(i8* %ap) - - 初始化 va_list。第二个参数 last_arg 在 LLVM intrinsic 中不使用(C 宏兼容)。 - """ - if can == 0 or cargs is None: - return llvmlite.const_int32(pool, 0) - - # 第一个参数:va_list 指针(获取 alloca,不 load) - ap_node: ast.AST | t.CPtr = cargs.get(0) - ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr( - pool, builder, mod, ap_node, funcs_ptr, func_count, trans) - if ap_ptr is None: - return llvmlite.const_int32(pool, 0) - - # bitcast 到 i8*(@llvm.va_start 接受 i8*) - i8_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_vs) - ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_vs) - if ap_i8 is None: - return llvmlite.const_int32(pool, 0) - - void_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - llvmlite.build_call(builder, "llvm.va_start", ap_i8, 1, void_ty_vs, 0) - return llvmlite.const_int32(pool, 0) - def _translate_va_end_sugar(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - cargs: list[ast.AST | t.CPtr] | t.CPtr, - can: t.CSizeT, - funcs_ptr: t.CPtr, - func_count: int, - trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: - """va_end(ap) → call void @llvm.va_end(i8* %ap) - - 清理 va_list。在大多数平台上是 no-op,但调用它是良好的 C ABI 习惯。 - """ - if can == 0 or cargs is None: - return llvmlite.const_int32(pool, 0) - - # 第一个参数:va_list 指针(获取 alloca,不 load) - ap_node: ast.AST | t.CPtr = cargs.get(0) - ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr( - pool, builder, mod, ap_node, funcs_ptr, func_count, trans) - if ap_ptr is None: - return llvmlite.const_int32(pool, 0) - - # bitcast 到 i8*(@llvm.va_end 接受 i8*) - i8_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_ve) - ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_ve) - if ap_i8 is None: - return llvmlite.const_int32(pool, 0) - - void_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - llvmlite.build_call(builder, "llvm.va_end", ap_i8, 1, void_ty_ve, 0) - return llvmlite.const_int32(pool, 0) - def _get_func_fixed_param_count(self, func: llvmlite.Function | t.CPtr) -> int: - """获取函数的固定参数数量(遍历 Params 链表)""" - if func is None: - return 0 - count: int = 0 - param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) - while param is not None: - count += 1 - param = llvmlite.param_get_next(param) - return count - def _check_and_promote_variadic_call(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - call_name: str, - head: llvmlite.Value | t.CPtr, - can: t.CSizeT, - arg_nodes: list[ast.AST | t.CPtr] | t.CPtr = None, - self_offset: int = 0, - trans: HT.Translator | t.CPtr = None) -> int: - """检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升 - - 返回: is_variadic (1=变长调用, 0=普通调用) - 副作用: 修改 head 链表中超过固定参数数量的节点(C ABI 提升) - - arg_nodes: 实参 AST 链表(不含 self),用于 i8/i16 提升的无符号性判断 - self_offset: Value 链中 self 占用的偏移(方法调用=1,普通函数=0) - trans: 供 _node_type_unsigned 查询变量注解 - """ - if mod is None or call_name is None or head is None: - return 0 - # 查找函数对象 - func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name) - if func is None: - return 0 - if func.IsVarArg != 1: - return 0 - - # 获取固定参数数量 - fixed_count: int = self._get_func_fixed_param_count(func) - - # 无变长参数(实参数量 <= 固定参数数量),仍需 is_variadic=1 - if can <= fixed_count: - return 1 - - # 遍历到第 fixed_count 个节点(固定参数的最后一个) - cur: llvmlite.Value | t.CPtr = head - prev: llvmlite.Value | t.CPtr = None - idx: int = 0 - while cur is not None and idx < fixed_count: - prev = cur - cur = cur.Next - idx += 1 - - # cur 指向第 fixed_count+1 个节点(第一个变长参数) - # 对变长参数进行 C ABI 提升 - i32_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - double_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) - v_idx: int = fixed_count - while cur is not None: - next_node: llvmlite.Value | t.CPtr = cur.Next - promoted: llvmlite.Value | t.CPtr = cur - # C ABI integer promotion: i8/i16 → i32 - arg_bits: int = HandlesExpr.get_llvm_type_bits(cur.Ty) - if arg_bits != 0 and arg_bits < 32: - # 无符号整型(t.CUInt8T/CUInt16T 等)→ zext;有符号/未知 → sext。 - # 修复: printf("%02x", buf[i]) 中 buf[i] 是 CUInt8T,sext 得 - # 0xFFFFFFF3 打印 fffffff3(哈希摘要输出垃圾),应 zext 得 0xF3。 - is_u_va: int = 0 - if arg_nodes is not None and trans is not None: - ast_idx_va: int = v_idx - self_offset - if ast_idx_va >= 0 and ast_idx_va < len(arg_nodes): - an_va: ast.AST | t.CPtr = arg_nodes.get(ast_idx_va) - if an_va is not None: - if HandlesExpr._node_type_unsigned(pool, an_va, trans) != 0: - is_u_va = 1 - if is_u_va != 0: - promoted = llvmlite.build_zext(builder, cur, i32_ty_promote) - else: - # is_u_va 判断失败(arg_nodes/trans 缺失或变量注解查不到)时, - # i8 按系统编程惯例默认 zext(对齐 should_zext_widen 的 - # "i8 → zext(系统编程中 i8 几乎总是无符号字节)"策略), - # 否则 printf("%02x", buf[i]) 中 uint8 字节被 sext 成 - # 0xFFFFFFF3,哈希摘要输出 ffffffXX 垃圾。 - if HandlesExpr.get_llvm_type_bits(cur.Ty) == 8: - promoted = llvmlite.build_zext(builder, cur, i32_ty_promote) - else: - promoted = HandlesExpr.coerce_to_type(builder, cur, i32_ty_promote, None) - if promoted is not None: - promoted.Next = next_node - if prev is not None: - prev.Next = promoted - # C ABI float promotion: float → double - arg_fbits: int = HandlesExpr.get_llvm_float_bits(promoted.Ty) - if arg_fbits != 0 and arg_fbits < 64: - promoted = HandlesExpr.coerce_to_type(builder, promoted, double_ty_promote, None) - if promoted is not None: - promoted.Next = next_node - if prev is not None: - prev.Next = promoted - prev = promoted - cur = next_node - v_idx += 1 - - return 1 - diff --git a/App/lib/core/Gen/CallGenProp.vp b/App/lib/core/Gen/CallGenProp.vp new file mode 100644 index 0000000..5639488 --- /dev/null +++ b/App/lib/core/Gen/CallGenProp.vp @@ -0,0 +1,455 @@ +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.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + +# ============================================================ +# CallGenProp - CallGenMixin 拆分(阶段 B):属性访问(getter/setter/deleter / 静态类调用 / list 内置方法) +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenProp(CallGenBase.CallGenBase): + """属性访问(getter/setter/deleter / 静态类调用 / list 内置方法)""" + + # ============================================================ + # _ensure_method_declare - 为跨模块方法调用创建 declare 声明 + # + # 当 found_func 为 None(stub 未注入或跨模块调用)时, + # 在当前模块中创建函数声明,避免 llc 报 undefined value。 + # ============================================================ + + # ============================================================ + # 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助 + # + # 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充, + # 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method() + # 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。 + # ============================================================ + + # ============================================================ + # _translate_property_call — 翻译属性方法调用 + # + # 与 _translate_method_call 的调用名/返回类型解析逻辑一致: + # 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入) + # 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名 + # 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32) + # + # call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数) + # ============================================================ + def _translate_property_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + call_head: llvmlite.Value | t.CPtr, + call_count: int, + 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 + + # 构造查找名: 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) + + # 查找函数(精确/后缀匹配) + 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: + # 未找到:用类所属模块的 SHA1 构造调用名 + cls_sha1_pc: str = HandlesStruct.get_struct_sha1(class_name) + if cls_sha1_pc is not None: + mlen_pc: t.CSizeT = string.strlen(cls_sha1_pc) + string.strlen(lookup_name) + 2 + mangled_pc: str = pool.alloc(mlen_pc) + if mangled_pc is not None: + viperlib.snprintf(mangled_pc, mlen_pc, "%s.%s", cls_sha1_pc, lookup_name) + call_name = mangled_pc + + # 确定返回类型 + 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: + sp_ty1: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name) + if sp_ty1 is not None: + call_ret_ty = sp_ty1 + else: + cls_sha1_rt: str = HandlesStruct.get_struct_sha1(class_name) + looked_up_ty: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( + pool, cls_sha1_rt, class_name, method_name) + if looked_up_ty is not None: + call_ret_ty = looked_up_ty + else: + # 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单) + vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi( + pool, cls_sha1_rt, class_name, method_name) + if vpi_ret_ty is not None: + call_ret_ty = vpi_ret_ty + else: + # Phase A 依赖未就绪(cls_sha1_rt None / 定义模块 text.ll 未生成): + # 标记 pending 下遍重译(对齐 _translate_method_call L4783-4790), + # 绝不 fail-fast 中断多遍收敛;真实错误由收敛检查兜底。 + if cls_sha1_rt is None \ + or self._dep_text_ll_exists(pool, cls_sha1_rt) == 0: + if trans is not None: + trans._deps_pending = 1 + call_ret_ty = llvmlite.Void(pool) + else: + call_ret_ty = self._fail_method_ret_ty(method_name) + + # 参数类型对齐:按目标函数声明的参数类型转换实参(与 _translate_method_call + # 一致)。例如 from_long(10) 的 i32 字面量 → i64 形参(v: t.CLong), + # 不转换则 call(i32) 与 declare(i64) 不匹配,llc 报参数类型错误。 + # 目标函数优先用已找到的 found_func,否则按 mangled 调用名查模块 declare。 + tgt_func_pc: llvmlite.Function | t.CPtr = found_func + if tgt_func_pc is None: + tgt_func_pc = self.find_func_in_module(mod, call_name) + if tgt_func_pc is not None: + prev_pc: llvmlite.Value | t.CPtr = None + cur_arg_pc: llvmlite.Value | t.CPtr = call_head + cur_param_pc: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(tgt_func_pc) + while cur_arg_pc is not None and cur_param_pc is not None: + param_ty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_pc) + if param_ty_pc is not None and cur_arg_pc.Ty is not None: + coerced_pc: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, cur_arg_pc, param_ty_pc) + if coerced_pc is not None and coerced_pc != cur_arg_pc: + # 保持链表完整性:新 Value 继承原节点的 Next,前驱指向新节点 + llvmlite.value_set_next(coerced_pc, cur_arg_pc.Next) + if prev_pc is None: + call_head = coerced_pc + else: + llvmlite.value_set_next(prev_pc, coerced_pc) + cur_arg_pc = coerced_pc + prev_pc = cur_arg_pc + cur_arg_pc = cur_arg_pc.Next + cur_param_pc = llvmlite.param_get_next(cur_param_pc) + + # 确保 declare 存在,然后调用 + self._ensure_method_declare(pool, mod, call_name, call_ret_ty, call_head, call_count) + return llvmlite.build_call(builder, call_name, call_head, call_count, call_ret_ty, 0) + # ============================================================ + # _resolve_obj_class_name — 解析对象表达式的类名(短名) + # + # 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"), + # 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。 + # 供属性访问/赋值/删除识别 property 时使用。 + # ============================================================ + + # ============================================================ + # _resolve_obj_class_name — 解析对象表达式的类名(短名) + # + # 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"), + # 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。 + # 供属性访问/赋值/删除识别 property 时使用。 + # ============================================================ + def _resolve_obj_class_name(self, pool: memhub.MemBuddy | t.CPtr, + trans: HT.Translator | t.CPtr, + obj_node: ast.AST | t.CPtr) -> str: + """解析对象表达式的类名(短名),失败返回 None""" + if pool is None or trans is None or obj_node is None: + return None + if obj_node.kind() == ast.ASTKind.Name: + obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(obj_node) + if obj_nm.id is not None: + var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, obj_nm.id) + if var_entry is not None and var_entry.AnnotClassName is not None: + annot_val: str = var_entry.AnnotClassName + dot_ptr: str = string.strrchr(annot_val, '.') + if dot_ptr is not None: + return dot_ptr + 1 + return annot_val + return None + # ============================================================ + # _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用 + # + # 检查 obj 的类是否有 @property/@x.getter 的 attr 方法; + # 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。 + # ============================================================ + + # ============================================================ + # _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用 + # + # 检查 obj 的类是否有 @property/@x.getter 的 attr 方法; + # 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。 + # ============================================================ + def _try_property_getter_attr(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + at_node: ast.Attribute | t.CPtr, + obj_ptr: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr, + fallback_class_name: str = None) -> llvmlite.Value | t.CPtr: + """尝试 property getter 属性访问,返回调用结果 Value;非 getter 返回 None + + fallback_class_name: 对象表达式非 Name 时从 LLVM 类型解析出的类名兜底。 + """ + if at_node is None or at_node.attr is None or obj_ptr is None or trans is None: + return None + class_name: str = self._resolve_obj_class_name(pool, trans, at_node.value) + if class_name is None: + class_name = fallback_class_name + if class_name is None: + return None + meta: int = HandlesClassDef.lookup_method_meta(class_name, at_node.attr) + if meta & HandlesClassDef.META_PROP_GETTER == 0: + return None + # 单参数调用: obj → getter + llvmlite.value_set_next(obj_ptr, None) + return self._translate_property_call( + pool, builder, mod, class_name, at_node.attr, obj_ptr, 1, trans) + # ============================================================ + # _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用 + # + # 检查 obj 的类是否有 @x.setter 的 attr 方法; + # 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。 + # ============================================================ + + # ============================================================ + # _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用 + # + # 检查 obj 的类是否有 @x.setter 的 attr 方法; + # 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。 + # ============================================================ + def _try_property_setter(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + target_attr: ast.Attribute | t.CPtr, + rhs_val: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr) -> int: + """尝试 property setter 赋值,返回 1=已处理(生成调用)""" + if pool is None or builder is None or mod is None or trans is None: + return 0 + if target_attr is None or target_attr.attr is None or rhs_val is None: + return 0 + class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value) + if class_name is None: + return 0 + meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr) + if meta & HandlesClassDef.META_PROP_SETTER == 0: + return 0 + # 翻译对象值(self 参数) + obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, target_attr.value, None, 0, trans) + if obj_val is None: + return 0 + # 构建参数链表: obj → rhs + llvmlite.value_set_next(obj_val, None) + llvmlite.value_set_next(rhs_val, None) + llvmlite.value_set_next(obj_val, rhs_val) + # setter 函数名带 $set 后缀 + setter_name_buf: str = pool.alloc(128) + if setter_name_buf is None: + return 0 + viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr) + self._translate_property_call(pool, builder, mod, class_name, + setter_name_buf, obj_val, 2, trans) + return 1 + # ============================================================ + # _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用 + # + # 检查 obj 的类是否有 @x.deleter 的 attr 方法; + # 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。 + # ============================================================ + + # ============================================================ + # _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用 + # + # 检查 obj 的类是否有 @x.deleter 的 attr 方法; + # 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。 + # ============================================================ + def _try_property_deleter(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + target_attr: ast.Attribute | t.CPtr, + trans: HT.Translator | t.CPtr) -> int: + """尝试 property deleter 删除,返回 1=已处理(生成调用)""" + if pool is None or builder is None or mod is None or trans is None: + return 0 + if target_attr is None or target_attr.attr is None: + return 0 + class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value) + if class_name is None: + return 0 + meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr) + if meta & HandlesClassDef.META_PROP_DELETER == 0: + return 0 + # 翻译对象值(self 参数) + obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, target_attr.value, None, 0, trans) + if obj_val is None: + return 0 + llvmlite.value_set_next(obj_val, None) + # deleter 函数名带 $del 后缀 + del_name_buf: str = pool.alloc(128) + if del_name_buf is None: + return 0 + viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr) + self._translate_property_call(pool, builder, mod, class_name, + del_name_buf, obj_val, 1, trans) + return 1 + # ============================================================ + # _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用 + # + # @staticmethod: 直接 call Class.method(args...),无 self + # @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致) + # ============================================================ + + # ============================================================ + # _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用 + # + # @staticmethod: 直接 call Class.method(args...),无 self + # @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致) + # ============================================================ + def _translate_static_class_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + class_name: str, + method_name: str, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """翻译类名静态/类方法调用,返回 call 结果 Value;非静态/类方法返回 None""" + if pool is None or builder is None or mod is None or trans is None: + return None + if class_name is None or method_name is None or cl is None: + return None + meta: int = HandlesClassDef.lookup_method_meta(class_name, method_name) + is_static: int = 0 + is_class: int = 0 + if meta & HandlesClassDef.META_STATIC != 0: + is_static = 1 + if meta & HandlesClassDef.META_CLASS != 0: + is_class = 1 + if is_static == 0 and is_class == 0: + return None + + # 构建参数链表 + head: llvmlite.Value | t.CPtr = None + total_count: int = 0 + + # @classmethod: 插入栈上分配的类实例指针作为 cls 参数 + if is_class != 0: + struct_ty_cc: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name) + if struct_ty_cc is None: + return None + cls_ptr: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty_cc) + if cls_ptr is None: + return None + llvmlite.value_set_next(cls_ptr, None) + head = cls_ptr + total_count = 1 + + # 翻译调用参数 + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = len(cargs) + tail: llvmlite.Value | t.CPtr = head + for ai in range(can): + arg_node: ast.AST | t.CPtr = cargs.get(ai) + if arg_node is None: + continue + arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg_node, None, 0, trans) + if arg_val is None: + continue + llvmlite.value_set_next(arg_val, None) + if head is None: + head = arg_val + tail = arg_val + else: + llvmlite.value_set_next(tail, arg_val) + tail = arg_val + total_count += 1 + + # 零参 @staticmethod(如 PyListObj.new()):head 保持 None 是合法的 + # 无参调用,照常走 _translate_property_call(SHA1 前缀名 + 精确返回类型)。 + # 若此处 return None,调用方回退通用路径把方法名当裸函数解析,生成 + # call i32 @new() → 链接 undefined reference(CPythonTest 根因)。 + # @classmethod 恒有 cls_ptr(head 非 None),不受影响。 + return self._translate_property_call(pool, builder, mod, class_name, + method_name, head, total_count, trans) + # ============================================================ + # _is_list_builtin_method - 判断是否是 list 泛型内置容器方法 + # + # list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/ + # __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list + # 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把 + # list 特化 struct(如 list[AST | CPtr])误当普通结构体走 + # _translate_method_call,会查不到 append 返回类型 → fail-fast + # (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。 + # + # 返回: 1=list 内置方法(应落到 list 内置分支),0=普通方法 + # ============================================================ + + # ============================================================ + # _is_list_builtin_method - 判断是否是 list 泛型内置容器方法 + # + # list[T] 是内置泛型容器(_list.vp),其方法(append/get/set/pop/clear/ + # __iter__/__len__/__getitem__/__setitem__)由 translate_call 的 list + # 内置分支内联 GEP 处理,不注册为方法函数。若 obj.method() 检测把 + # list 特化 struct(如 list[AST | CPtr])误当普通结构体走 + # _translate_method_call,会查不到 append 返回类型 → fail-fast + # (NewAstTest body.append 根因)。此判断用于跳过 method_call 路径。 + # + # 返回: 1=list 内置方法(应落到 list 内置分支),0=普通方法 + # ============================================================ + def _is_list_builtin_method(self, class_name: str, + method_name: str) -> int: + """判断 (class_name, method_name) 是否是 list 泛型内置方法""" + if class_name is None or method_name is None: + return 0 + # 类名必须以 "list" 开头(list / list[AST | CPtr] 特化名) + if string.strncmp(class_name, "list", 4) != 0: + return 0 + # 方法名必须是 list 内置方法集合 + if string.strcmp(method_name, "append") == 0: return 1 + if string.strcmp(method_name, "get") == 0: return 1 + if string.strcmp(method_name, "set") == 0: return 1 + if string.strcmp(method_name, "pop") == 0: return 1 + if string.strcmp(method_name, "clear") == 0: return 1 + if string.strcmp(method_name, "__iter__") == 0: return 1 + if string.strcmp(method_name, "__len__") == 0: return 1 + if string.strcmp(method_name, "__getitem__") == 0: return 1 + if string.strcmp(method_name, "__setitem__") == 0: return 1 + return 0 \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenVa.vp b/App/lib/core/Gen/CallGenVa.vp new file mode 100644 index 0000000..e80e0cd --- /dev/null +++ b/App/lib/core/Gen/CallGenVa.vp @@ -0,0 +1,334 @@ +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.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + +# ============================================================ +# CallGenVa - CallGenMixin 拆分(阶段 B):va_arg 变长参数(start/arg/end / 变长调用提升) +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenVa(CallGenBase.CallGenBase): + """va_arg 变长参数(start/arg/end / 变长调用提升)""" + + # ============================================================ + # _func_has_eh_params - 被调函数签名是否含 try-except EH 输出参数 + # + # EH 参数(%__eh_msg_out__/__eh_code_out__)由 translate_function_def/ + # _translate_method 在含 raise 的函数签名末尾注入(main 除外)。 + # ============================================================ + + def _va_arg_get_alloca_ptr(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + arg_node: ast.AST | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """获取 va_list 变量的 alloca 指针(不 load) + + va_arg/va_start/va_end 需要的是 va_list 对象的地址(alloca 指针), + 而非 va_list 的值。若 arg_node 是 Name,查符号表获取 alloca; + 否则用 translate_value 翻译(调用者负责确保传入的是指针)。 + """ + if arg_node is None: + return None + # Name 节点:直接查符号表获取 alloca 指针(不 load) + if arg_node.kind() == ast.ASTKind.Name: + nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg_node) + if nm.id is not None: + alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id) + if alloca is not None: + return alloca + # 回退:translate_value(可能返回 load 后的值,仅适用于已是指针的情况) + return HandlesExpr.translate_value(builder, pool, mod, arg_node, funcs_ptr, func_count, trans) + def _resolve_va_arg_type(self, pool: memhub.MemBuddy | t.CPtr, + type_node: ast.AST | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr: + """解析 va_arg/arg 的类型参数为 LLVMType + + 支持的类型表达式: + t.CInt / t.CInt32T → i32 + t.CInt64T → i64 + t.CDouble → double + t.CPtr / str → i8* + str / bytes → i8* + 无类型参数时默认 i32(vsnprintf 中 va_arg(ap) 常用于读取 i32) + """ + if type_node is None: + return llvmlite.Int32(pool) + # 使用 HandlesType.resolve_annotation_type 解析类型表达式 + resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type( + pool, type_node, trans._imported_modules, trans._from_imports, trans) + if resolved is not None: + return resolved + # 类型节点存在但解析失败:fail-fast,绝不回退 i32(会按错宽度读变参槽位) + HandlesType.fatal_error(type_node, "va_arg 类型解析失败", "TypeError") + return llvmlite.Int32(pool) + def _translate_va_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """va_arg(ap, type) / va_arg(ap) → %N = va_arg , + + 生成 LLVM va_arg 指令,从 va_list 读取下一个变长参数。 + """ + if can == 0 or cargs is None: + return llvmlite.const_int32(pool, 0) + + # 第一个参数:va_list(求值为 i8* 地址值,对齐 TPC _HandleVaArgLlvm) + # 当前函数 *args:translate_value 经 vararg 名映射直接返回 va_list 缓冲区地址; + # 转发场景(sprintf → vsnprintf 的 ap 参数):translate_value load 参数得到地址值。 + ap_node: ast.AST | t.CPtr = cargs.get(0) + ap_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, ap_node, None, 0, trans) + if ap_val is None: + return llvmlite.const_int32(pool, 0) + ap_ptr: llvmlite.Value | t.CPtr = ap_val + + # 第二个参数:目标类型(可选,默认 i32) + arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if can >= 2: + type_node: ast.AST | t.CPtr = cargs.get(1) + arg_ty = self._resolve_va_arg_type(pool, type_node, trans) + + # Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(对齐 TPC emit_va_arg L72-73) + read_ty: llvmlite.LLVMType | t.CPtr = arg_ty + abits_va: int = HandlesExpr.get_llvm_type_bits(arg_ty) + if abits_va != 0 and abits_va < 64: + read_ty = llvmlite.Int64(pool) + + # 生成 va_arg 指令 + return llvmlite.build_va_arg(builder, ap_ptr, read_ty) + def _translate_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """arg(type) → %N = va_arg , + + 使用当前函数的隐式 va_list(trans._va_list_ptr), + 简化 *args 函数体内的 va_arg 调用。 + """ + if trans._va_list_ptr is None: + return llvmlite.const_int32(pool, 0) + + # 第一个参数:目标类型(可选,默认 i32) + arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + if can >= 1 and cargs is not None: + type_node: ast.AST | t.CPtr = cargs.get(0) + arg_ty = self._resolve_va_arg_type(pool, type_node, trans) + + # Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(与 _translate_va_arg_sugar 一致) + read_ty: llvmlite.LLVMType | t.CPtr = arg_ty + abits_arg: int = HandlesExpr.get_llvm_type_bits(arg_ty) + if abits_arg != 0 and abits_arg < 64: + read_ty = llvmlite.Int64(pool) + + # 生成 va_arg 指令(使用 trans._va_list_ptr 作为 va_list 地址) + return llvmlite.build_va_arg(builder, trans._va_list_ptr, read_ty) + def _translate_va_start_sugar(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """va_start(ap, last_arg) → call void @llvm.va_start(i8* %ap) + + 初始化 va_list。第二个参数 last_arg 在 LLVM intrinsic 中不使用(C 宏兼容)。 + """ + if can == 0 or cargs is None: + return llvmlite.const_int32(pool, 0) + + # 第一个参数:va_list 指针(获取 alloca,不 load) + ap_node: ast.AST | t.CPtr = cargs.get(0) + ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr( + pool, builder, mod, ap_node, funcs_ptr, func_count, trans) + if ap_ptr is None: + return llvmlite.const_int32(pool, 0) + + # bitcast 到 i8*(@llvm.va_start 接受 i8*) + i8_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_vs) + ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_vs) + if ap_i8 is None: + return llvmlite.const_int32(pool, 0) + + void_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + llvmlite.build_call(builder, "llvm.va_start", ap_i8, 1, void_ty_vs, 0) + return llvmlite.const_int32(pool, 0) + def _translate_va_end_sugar(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """va_end(ap) → call void @llvm.va_end(i8* %ap) + + 清理 va_list。在大多数平台上是 no-op,但调用它是良好的 C ABI 习惯。 + """ + if can == 0 or cargs is None: + return llvmlite.const_int32(pool, 0) + + # 第一个参数:va_list 指针(获取 alloca,不 load) + ap_node: ast.AST | t.CPtr = cargs.get(0) + ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr( + pool, builder, mod, ap_node, funcs_ptr, func_count, trans) + if ap_ptr is None: + return llvmlite.const_int32(pool, 0) + + # bitcast 到 i8*(@llvm.va_end 接受 i8*) + i8_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_ve) + ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_ve) + if ap_i8 is None: + return llvmlite.const_int32(pool, 0) + + void_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + llvmlite.build_call(builder, "llvm.va_end", ap_i8, 1, void_ty_ve, 0) + return llvmlite.const_int32(pool, 0) + def _get_func_fixed_param_count(self, func: llvmlite.Function | t.CPtr) -> int: + """获取函数的固定参数数量(遍历 Params 链表)""" + if func is None: + return 0 + count: int = 0 + param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func) + while param is not None: + count += 1 + param = llvmlite.param_get_next(param) + return count + def _check_and_promote_variadic_call(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + call_name: str, + head: llvmlite.Value | t.CPtr, + can: t.CSizeT, + arg_nodes: list[ast.AST | t.CPtr] | t.CPtr = None, + self_offset: int = 0, + trans: HT.Translator | t.CPtr = None) -> int: + """检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升 + + 返回: is_variadic (1=变长调用, 0=普通调用) + 副作用: 修改 head 链表中超过固定参数数量的节点(C ABI 提升) + + arg_nodes: 实参 AST 链表(不含 self),用于 i8/i16 提升的无符号性判断 + self_offset: Value 链中 self 占用的偏移(方法调用=1,普通函数=0) + trans: 供 _node_type_unsigned 查询变量注解 + """ + if mod is None or call_name is None or head is None: + return 0 + # 查找函数对象 + func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name) + if func is None: + return 0 + if func.IsVarArg != 1: + return 0 + + # 获取固定参数数量 + fixed_count: int = self._get_func_fixed_param_count(func) + + # 无变长参数(实参数量 <= 固定参数数量),仍需 is_variadic=1 + if can <= fixed_count: + return 1 + + # 遍历到第 fixed_count 个节点(固定参数的最后一个) + cur: llvmlite.Value | t.CPtr = head + prev: llvmlite.Value | t.CPtr = None + idx: int = 0 + while cur is not None and idx < fixed_count: + prev = cur + cur = cur.Next + idx += 1 + + # cur 指向第 fixed_count+1 个节点(第一个变长参数) + # 对变长参数进行 C ABI 提升 + i32_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + double_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool) + v_idx: int = fixed_count + while cur is not None: + next_node: llvmlite.Value | t.CPtr = cur.Next + promoted: llvmlite.Value | t.CPtr = cur + # C ABI integer promotion: i8/i16 → i32 + arg_bits: int = HandlesExpr.get_llvm_type_bits(cur.Ty) + if arg_bits != 0 and arg_bits < 32: + # 无符号整型(t.CUInt8T/CUInt16T 等)→ zext;有符号/未知 → sext。 + # 修复: printf("%02x", buf[i]) 中 buf[i] 是 CUInt8T,sext 得 + # 0xFFFFFFF3 打印 fffffff3(哈希摘要输出垃圾),应 zext 得 0xF3。 + is_u_va: int = 0 + if arg_nodes is not None and trans is not None: + ast_idx_va: int = v_idx - self_offset + if ast_idx_va >= 0 and ast_idx_va < len(arg_nodes): + an_va: ast.AST | t.CPtr = arg_nodes.get(ast_idx_va) + if an_va is not None: + if HandlesExpr._node_type_unsigned(pool, an_va, trans) != 0: + is_u_va = 1 + if is_u_va != 0: + promoted = llvmlite.build_zext(builder, cur, i32_ty_promote) + else: + # is_u_va 判断失败(arg_nodes/trans 缺失或变量注解查不到)时, + # i8 按系统编程惯例默认 zext(对齐 should_zext_widen 的 + # "i8 → zext(系统编程中 i8 几乎总是无符号字节)"策略), + # 否则 printf("%02x", buf[i]) 中 uint8 字节被 sext 成 + # 0xFFFFFFF3,哈希摘要输出 ffffffXX 垃圾。 + if HandlesExpr.get_llvm_type_bits(cur.Ty) == 8: + promoted = llvmlite.build_zext(builder, cur, i32_ty_promote) + else: + promoted = HandlesExpr.coerce_to_type(builder, cur, i32_ty_promote, None) + if promoted is not None: + promoted.Next = next_node + if prev is not None: + prev.Next = promoted + # C ABI float promotion: float → double + arg_fbits: int = HandlesExpr.get_llvm_float_bits(promoted.Ty) + if arg_fbits != 0 and arg_fbits < 64: + promoted = HandlesExpr.coerce_to_type(builder, promoted, double_ty_promote, None) + if promoted is not None: + promoted.Next = next_node + if prev is not None: + prev.Next = promoted + prev = promoted + cur = next_node + v_idx += 1 + + return 1 \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenVt.vp b/App/lib/core/Gen/CallGenVt.vp new file mode 100644 index 0000000..924bc40 --- /dev/null +++ b/App/lib/core/Gen/CallGenVt.vp @@ -0,0 +1,251 @@ +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.core.Handles.HandlesVar as HandlesVar +import lib.core.Handles.HandlesType as HandlesType +import lib.core.Handles.HandlesNonlocal as HandlesNonlocal +import lib.core.Handles.HandlesStruct as HandlesStruct +import lib.core.Handles.HandlesImports as HandlesImports +import lib.core.Handles.HandlesClassDef as HandlesClassDef +import lib.core.Handles.HandlesFunctions as HandlesFunctions +import lib.core.StubMerger as StubMerger +import lib.core.Handles.HandlesExprCall as HandlesExprCall +import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign +import lib.core.CompilerFactory as CompilerFactory + + +import lib.core.Gen.CallGenBase as CallGenBase + +# ============================================================ +# CallGenVt - CallGenMixin 拆分(阶段 B):vtable 槽位写入 +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenVt(CallGenBase.CallGenBase): + """vtable 槽位写入""" + + # ============================================================ + # _write_vtable_slot / _write_vtable_attr — vtable 方法槽位直接写入 + # + # serial0_file.open = serial0_open(devfs 驱动注册模式):把模块级函数 + # 指针写入对象 vtable 的方法槽位。vtable 方法不是数据字段(FieldEntry), + # get_attribute_ptr 查不到 → 此前 fatal_error "属性写入失败"。 + # 对齐 TPC HandlesAssign.py L905-949 的写时复制: + # 对象 vtable 仍指向类默认 vtable 时,先复制一份(internal 全局 + + # llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store + # 函数指针(i8*)。多次写入互不覆盖(第二次起 vtable 已非默认, + # 跳过复制直接写槽位)。 + # ============================================================ + + # ============================================================ + # _write_vtable_slot / _write_vtable_attr — vtable 方法槽位直接写入 + # + # serial0_file.open = serial0_open(devfs 驱动注册模式):把模块级函数 + # 指针写入对象 vtable 的方法槽位。vtable 方法不是数据字段(FieldEntry), + # get_attribute_ptr 查不到 → 此前 fatal_error "属性写入失败"。 + # 对齐 TPC HandlesAssign.py L905-949 的写时复制: + # 对象 vtable 仍指向类默认 vtable 时,先复制一份(internal 全局 + + # llvm.memcpy)并让对象指向副本,再 GEP method_index 槽位 store + # 函数指针(i8*)。多次写入互不覆盖(第二次起 vtable 已非默认, + # 跳过复制直接写槽位)。 + # ============================================================ + def _write_vtable_slot(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + obj_ptr: llvmlite.Value | t.CPtr, + class_name: str, + method_index: int, + func_val: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr) -> int: + """生成 vtable 槽位写入(写时复制),成功返回 1""" + if pool is None or builder is None or mod is None or trans is None: + return 0 + if obj_ptr is None or class_name is None or func_val is None: + return 0 + if method_index < 0 or trans._cur_func is None: + return 0 + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + if i8_ty is None: + return 0 + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + if i8_ptr_ty is None: + return 0 + i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty) + if i8_ptr_ptr_ty is None: + return 0 + method_count: int = HandlesStruct.get_vtable_method_count(class_name) + if method_count <= 0: + return 0 + # 构造 vtable 类型 { i8*, i8*, ... } + 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 0 + # 对象 vtable 槽位(对象头 → i8**,vtable 指针总是第一个字段) + vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, obj_ptr, i8_ptr_ptr_ty) + if vtable_slot is None: + return 0 + vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty, vtable_slot) + if vtable_ptr is None: + return 0 + # 类默认 vtable 地址(比较用) + class_vt: llvmlite.Value | t.CPtr = HandlesExprCall._make_vtable_ref_i8( + pool, builder, mod, class_name, trans) + if class_vt is None: + return 0 + cmp_vt: llvmlite.Value | t.CPtr = llvmlite.build_icmp( + builder, llvmlite.ICMP_EQ, vtable_ptr, class_vt) + if cmp_vt is None: + return 0 + # 块名唯一化(create_block 不自动编号;同函数多次 vtable 写入(如 + # devfs open/close/read/write 连续赋值)同名 label 冲突) + vtc3: int = trans._label_counter + trans._label_counter = vtc3 + 1 + vt_bb_buf3: str = pool.alloc(64) + if vt_bb_buf3 is None: + return 0 + viperlib.snprintf(vt_bb_buf3, 64, "vt.copy.%d", vtc3) + vt_copy_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, trans._cur_func, vt_bb_buf3) + viperlib.snprintf(vt_bb_buf3, 64, "vt.skip.%d", vtc3) + vt_skip_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block( + pool, trans._cur_func, vt_bb_buf3) + if vt_copy_bb is None or vt_skip_bb is None: + return 0 + llvmlite.build_cond_br(builder, cmp_vt, vt_copy_bb, vt_skip_bb) + # copy 块:创建 internal 副本全局(zeroinit)+ memcpy + 对象指向副本 + llvmlite.position_at_end(builder, vt_copy_bb) + vtc: int = trans._label_counter + trans._label_counter = vtc + 1 + vcopy_buf: str = pool.alloc(256) + if vcopy_buf is not None: + viperlib.snprintf(vcopy_buf, 256, "%s.vtable.copy.%d", class_name, vtc) + vcopy_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable( + pool, vcopy_buf, vtable_ty) + if vcopy_gv is not None: + llvmlite.module_add_global(mod, vcopy_gv) + vcopy_gv.Linkage = None + vcopy_gv.Initializer = "zeroinitializer" + vcopy_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue( + pool, llvmlite.Ptr(pool, vtable_ty), vcopy_buf) + if vcopy_ref is not None: + vcopy_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, vcopy_ref, i8_ptr_ty) + if vcopy_i8 is not None: + vt_size: llvmlite.Value | t.CPtr = llvmlite.ConstInt( + pool, llvmlite.Int64(pool), method_count * 8, "vtsz") + if vt_size is not None: + HandlesExprCall._emit_llvm_memcpy_intrinsic( + pool, builder, mod, vcopy_i8, class_vt, vt_size) + llvmlite.build_store(builder, vcopy_i8, vtable_slot) + llvmlite.build_br(builder, vt_skip_bb) + # skip 块:reload vtable → GEP 槽位 → store 函数指针(i8*) + llvmlite.position_at_end(builder, vt_skip_bb) + vt_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty, vtable_slot) + if vt_ptr2 is None: + return 0 + vt_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, vt_ptr2, llvmlite.Ptr(pool, vtable_ty)) + if vt_typed is None: + return 0 + vt_slotp: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct( + builder, vtable_ty, i8_ptr_ty, vt_typed, method_index) + if vt_slotp is None: + return 0 + fptr_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, func_val, i8_ptr_ty) + if fptr_i8 is not None: + llvmlite.build_store(builder, fptr_i8, vt_slotp) + return 1 + def _write_vtable_attr(self, builder: llvmlite.IRBuilder | t.CPtr, + pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + node: ast.AST | t.CPtr, + rhs_val: llvmlite.Value | t.CPtr, + trans: HT.Translator | t.CPtr) -> int: + """属性写入 obj.method = func:检测 vtable 方法并生成槽位写入(成功返回 1)""" + if node is None or builder is None or pool is None or mod is None: + return 0 + if rhs_val is None or trans is None: + return 0 + at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node) + if at is None or at.value is None or at.attr is None: + return 0 + # 解析类名(AnnotClassName;去模块前缀) + class_nm_v: str = None + if at.value.kind() == ast.ASTKind.Name: + nm_v: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value) + if nm_v.id is not None: + ve_v: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, nm_v.id) + if ve_v is not None: + class_nm_v = ve_v.AnnotClassName + elif at.value.kind() == ast.ASTKind.Attribute: + # 跨 Mixin:_resolve_attr_field_class 定义在 ExprGenMixin,经 gen 单例调用 + import lib.core.Gen.Generator as Generator + g_vta: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( + t.CVoid(HandlesExpr._g_gen, t.CPtr)) + if g_vta is not None: + class_nm_v = g_vta._resolve_attr_field_class(pool, trans, at.value) + if class_nm_v is None: + return 0 + fd_dot_v: str = string.strrchr(class_nm_v, '.') + if fd_dot_v is not None: + class_nm_v = fd_dot_v + 1 + if HandlesStruct.get_struct_type(class_nm_v) is None: + return 0 + vm_idx_v: int = HandlesStruct.get_vtable_method_index(class_nm_v, at.attr) + if vm_idx_v < 0: + return 0 + # 解析 obj_ptr(对齐 get_attribute_ptr 前半段:Name 直接查 alloca) + obj_ptr_v: llvmlite.Value | t.CPtr = None + if at.value.kind() == ast.ASTKind.Name: + obj_ptr_v = HandlesVar.lookup_var( + trans.SymTab, ((ast.Name | t.CPtr)(at.value)).id) + else: + obj_ptr_v = HandlesExpr.translate_value( + builder, pool, mod, at.value, None, 0, trans) + if obj_ptr_v is None or obj_ptr_v.Ty is None: + return 0 + # X|t.CPtr 变量(Ptr(Ptr))load 解引用取对象指针 + match obj_ptr_v.Ty: + case llvmlite.LLVMType.Ptr(inner_v): + match inner_v: + case llvmlite.LLVMType.Ptr(_): + obj_ptr_v = llvmlite.build_load(builder, inner_v, obj_ptr_v) + case _: + pass + case _: + pass + if obj_ptr_v is None: + return 0 + return self._write_vtable_slot( + pool, builder, mod, obj_ptr_v, class_nm_v, vm_idx_v, rhs_val, trans) \ No newline at end of file diff --git a/App/lib/core/Gen/Generator.vp b/App/lib/core/Gen/Generator.vp index f78a41e..e29af92 100644 --- a/App/lib/core/Gen/Generator.vp +++ b/App/lib/core/Gen/Generator.vp @@ -10,6 +10,12 @@ import lib.core.Gen.CallGenMixin as CallGenMixin import lib.core.Gen.CallGenBase as CallGenBase import lib.core.Gen.CallGenLeafKit as CallGenLeafKit import lib.core.Gen.CallGenCBuiltin as CallGenCBuiltin +import lib.core.Gen.CallGenCtor as CallGenCtor +import lib.core.Gen.CallGenCall as CallGenCall +import lib.core.Gen.CallGenProp as CallGenProp +import lib.core.Gen.CallGenFd as CallGenFd +import lib.core.Gen.CallGenVt as CallGenVt +import lib.core.Gen.CallGenVa as CallGenVa import lib.core.Gen.FuncGenMixin as FuncGenMixin import lib.core.Gen.ClassGenMixin as ClassGenMixin import lib.core.Gen.ImportsGenMixin as ImportsGenMixin @@ -38,6 +44,9 @@ class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin, StructGenMixin.StructGenMixin, ExprGenMixin.ExprGenMixin, CallGenMixin.CallGenMixin, CallGenBase.CallGenBase, CallGenLeafKit.CallGenLeafKit, CallGenCBuiltin.CallGenCBuiltin, + CallGenCtor.CallGenCtor, CallGenCall.CallGenCall, + CallGenProp.CallGenProp, CallGenFd.CallGenFd, + CallGenVt.CallGenVt, CallGenVa.CallGenVa, FuncGenMixin.FuncGenMixin, ClassGenMixin.ClassGenMixin, ImportsGenMixin.ImportsGenMixin, StmtGenMixin.StmtGenMixin, AssignGenMixin.AssignGenMixin, diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index 9d59467..6faf8a5 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -1816,3 +1816,54 @@ def _translate_isinstance(pool: memhub.MemBuddy | t.CPtr, if g is not None: return g._translate_isinstance(pool, builder, mod, obj_node, cls_node, trans) return None + + +# ============================================================ +# _is_sha1_mangled_call / _is_list_builtin_method / _translate_fakeduck_call / +# _translate_super_call(阶段 B:CallGenMixin 拆分后顶层经委托调用这些方法) +# ============================================================ +def _is_sha1_mangled_call(call_name: str) -> int: + """判断 call_name 是否为跨模块 Viper 函数(委托到 gen._is_sha1_mangled_call)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._is_sha1_mangled_call(call_name) + return 0 + + +def _is_list_builtin_method(class_name: str, method_name: str) -> int: + """判断 (class_name, method_name) 是否是 list 泛型内置方法(委托到 gen._is_list_builtin_method)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._is_list_builtin_method(class_name, method_name) + return 0 + + +def _translate_fakeduck_call(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cls_name: str, + method_name: str, + cl: ast.Call | t.CPtr, + trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr: + """FakeDuck: str 变量方法调用(委托到 gen._translate_fakeduck_call)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._translate_fakeduck_call(pool, builder, mod, cls_name, method_name, cl, trans) + return None + + +def _translate_super_call(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) → 父类方法静态调用(委托到 gen._translate_super_call)""" + import lib.core.Gen.Generator as Generator + g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr)) + if g is not None: + return g._translate_super_call(pool, builder, mod, cl, method_name, trans) + return None