From 9f19bb3666d3a15935dff5ad4c1fb3a468dce4f8 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 17 Aug 2026 06:59:14 +0800 Subject: [PATCH] =?UTF-8?q?refactor(gen):=20CallGenMixin=20=E9=98=B6?= =?UTF-8?q?=E6=AE=B5=20C=20=E6=8B=86=20translate=5Fcall=20=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=E6=AE=B5=EF=BC=88Dispatch=206=20helper=EF=BC=89+=20?= =?UTF-8?q?=E8=BE=85=E5=8A=A9=E6=96=B9=E6=B3=95=EF=BC=88Lib=EF=BC=89?= =?UTF-8?q?=EF=BC=8C=E9=A1=B6=E5=B1=82=E9=99=8D=E8=87=B3=201119=20?= =?UTF-8?q?=E8=A1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/lib/core/Gen/CallGenDispatch.vp | 1433 +++++++++++++++++ App/lib/core/Gen/CallGenLib.vp | 578 +++++++ App/lib/core/Gen/CallGenMixin.vp | 1946 +---------------------- App/lib/core/Gen/Generator.vp | 3 + App/lib/core/Handles/HandlesExprCall.vp | 112 ++ 5 files changed, 2164 insertions(+), 1908 deletions(-) create mode 100644 App/lib/core/Gen/CallGenDispatch.vp create mode 100644 App/lib/core/Gen/CallGenLib.vp diff --git a/App/lib/core/Gen/CallGenDispatch.vp b/App/lib/core/Gen/CallGenDispatch.vp new file mode 100644 index 0000000..c396f71 --- /dev/null +++ b/App/lib/core/Gen/CallGenDispatch.vp @@ -0,0 +1,1433 @@ +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 + +# ============================================================ +# CallGenDispatch - CallGenMixin 拆分(阶段 C):translate_call 检测段 +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 每个 helper 返回 Value|CPtr,None = 未命中(translate_call 继续)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenDispatch(CallGenBase.CallGenBase): + """translate_call 前置检测 helper(继承 Base)""" + + def _tc_h1_super_ctraits(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """super()/ctraits 编译期检测(未命中返回 None)""" + # super() 语义(2026-08-10):super().method(args) → 静态调用父类方法 + # 形态: Call(func=Attribute(value=Call(func=Name('super')), attr=method)) + # 必须在 Attribute 分派前拦截——否则 value 的 Call(super) 被 translate_value + # 当作普通函数调用报错,且走普通属性调用会命中自身/虚分派而非父类实现。 + if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + sup_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if sup_at.value is not None and sup_at.value.kind() == ast.ASTKind.Call: + sup_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(sup_at.value) + 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 HandlesExprCall._translate_super_call( + pool, builder, mod, cl, func_name, trans) + + # ctraits 宏库编译期谓词:ctraits.isptr(x) 不生成运行时调用, + # 直接按变量存储类型返回编译期常量(CIf 求值失败回退或非 CIf 上下文时兜底, + # 避免生成跨模块调用 ctraits.isptr 触发"模块未注册 SHA1"误导性报错) + if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + ct_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if ct_at.value is not None and ct_at.value.kind() == ast.ASTKind.Name: + ct_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_at.value) + if ct_nm.id is not None and string.strcmp(ct_nm.id, "ctraits") == 0 \ + and string.strcmp(func_name, "isptr") == 0: + ct_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if ct_args is not None and len(ct_args) >= 1: + ct_arg0: ast.AST | t.CPtr = ct_args.get(0) + if ct_arg0 is not None and ct_arg0.kind() == ast.ASTKind.Name: + ct_nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_arg0) + if ct_nm0.id is not None and trans is not None: + ct_r: int = HandlesType.eval_ctraits_isptr(trans.SymTab, ct_nm0.id) + if ct_r > 0: + return llvmlite.const_int32(pool, 1) + return llvmlite.const_int32(pool, 0) + return None + + def _tc_h2_c_special(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """c.Deref/Asm/LLVMIR 等特殊调用(未命中返回 None)""" + # 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR,不生成 call) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + at_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if at_node.value is not None and at_node.value.kind() == ast.ASTKind.Name: + mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_node.value) + if mod_nm.id is not None and string.strcmp(mod_nm.id, "c") == 0: + if string.strcmp(func_name, "Deref") == 0: + return HandlesExprCall.translate_c_deref(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "DerefAs") == 0: + return HandlesExprCall.translate_c_derefas(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Addr") == 0: + return HandlesExprCall.translate_c_addr(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Set") == 0: + # c.Set(a, b) = a = b(赋值语义,非指针解引用)。 + # 若当普通函数调用会生成 @Set 引用导致链接失败(undefined reference to `Set')。 + return HandlesExprCall.translate_c_set(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Load") == 0: + return HandlesExprCall.translate_c_load(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "Asm") == 0: + return HandlesExprCall.translate_c_asm(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "LLVMIR") == 0: + return HandlesExprCall.translate_c_llvmir(pool, builder, mod, cl, trans) + elif string.strcmp(func_name, "LInp") == 0 or string.strcmp(func_name, "LOut") == 0: + # c.LInp/c.LOut 独立调用时返回 0(仅在 c.LLVMIR 的 f-string 内有意义) + return llvmlite.ConstInt(pool, llvmlite.Int32(pool), 0, "0") + elif string.strcmp(func_name, "CIf") == 0: + # 运行时 c.CIf(expr)(编译期求值失败回退):expr 与 0 比较得到 i1 + # 对齐 TPC HandlesExprCall.py L2434-2444 + cif_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args + if cif_args is not None and len(cif_args) >= 1: + cif_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cif_args.get(0), funcs_ptr, func_count, trans) + if cif_arg_val is not None: + cif_bits: int = HandlesExpr.get_llvm_type_bits(cif_arg_val.Ty) + if cif_bits == 1: + return cif_arg_val + if HandlesExpr.is_ptr_type(cif_arg_val.Ty) != 0: + cif_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( + pool, cif_arg_val.Ty, "null") + return llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cif_arg_val, cif_null) + cif_zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) + return llvmlite.build_icmp( + builder, llvmlite.ICMP_NE, cif_arg_val, cif_zero) + return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "0") + elif string.strcmp(func_name, "CIfdef") == 0 or string.strcmp(func_name, "CIfndef") == 0: + # 运行时 c.CIfdef/c.CIfndef(编译期求值失败回退):恒真 + # 对齐 TPC HandlesExprCall.py L2445-2446 + return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 1, "1") + return None + + def _tc_h3_stdarg_cast(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """stdarg 糖 + str/int/bool 内置强转(未命中返回 None)""" + # stdarg 糖函数处理: va_arg / arg / va_start / va_end + # 这些函数在 stdarg.vp 中声明为 pass 体,由编译器在翻译期处理: + # va_arg(ap, type) → %N = va_arg , (LLVM 指令) + # va_arg(ap) → 同上,类型从赋值上下文推断(默认 i32) + # arg(type) → 同上,使用当前函数的隐式 va_list (trans._va_list_ptr) + # va_start(ap, _) → call void @llvm.va_start(i8* %ap) (LLVM intrinsic) + # va_end(ap) → call void @llvm.va_end(i8* %ap) (LLVM intrinsic) + # ============================================================ + if func_name is not None and trans is not None: + if string.strcmp(func_name, "va_arg") == 0: + return HandlesExprCall._translate_va_arg_sugar(pool, builder, mod, cl, cargs, can, + funcs_ptr, func_count, trans) + elif string.strcmp(func_name, "arg") == 0: + return HandlesExprCall._translate_arg_sugar(pool, builder, mod, cl, cargs, can, + funcs_ptr, func_count, trans) + elif string.strcmp(func_name, "va_start") == 0: + return HandlesExprCall._translate_va_start_sugar(pool, builder, mod, cargs, can, + funcs_ptr, func_count, trans) + elif string.strcmp(func_name, "va_end") == 0: + return HandlesExprCall._translate_va_end_sugar(pool, builder, mod, cargs, can, + funcs_ptr, func_count, trans) + + # 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32 + # 等价于 (str)(x) / (t.CInt32T)(x) + # 单参数:str(val) → bitcast val to i8* + # int(val) → trunc/sext val to i32 + # 泛型类型参数: 类特化/泛型函数上下文中的 T(x) 先解析 T 为具体类型名 + # (如 "int")再按内建强转处理(Box[int].__init__ 的 self.value = T(v)、 + # combine[T1,T2] 的 T1(b) 依赖此路径) + if func_name is not None and can == 1: + cast_fn_name: str = HandlesType.resolve_generic_type_name(func_name) + if string.strcmp(cast_fn_name, "str") == 0 or string.strcmp(cast_fn_name, "bytes") == 0: + # str(x) / bytes(x) → i8* (bitcast) + cast_arg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + 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 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 + cast_arg_int: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + 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 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 归一化) + # 整数: icmp ne x, 0 → i1 + # 浮点: fcmp one x, 0.0 → i1 + # 指针: icmp ne x, null → i1 + cast_arg_bool: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) + if cast_arg_bool is not None: + arg_bits: int = HandlesExpr.get_llvm_type_bits(cast_arg_bool.Ty) + arg_fbits: int = HandlesExpr.get_llvm_float_bits(cast_arg_bool.Ty) + # 整数: icmp ne x, 0 + if arg_bits != 0: + zero_int: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, arg_bits, 0) + if zero_int is not None: + return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, zero_int) + return None + # 浮点: fcmp one x, 0.0 + if arg_fbits != 0: + zero_ty: llvmlite.LLVMType | t.CPtr = cast_arg_bool.Ty + zero_flt: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, zero_ty, 0.0) + if zero_flt is not None: + return llvmlite.build_fcmp(builder, llvmlite.FCMP_ONE, cast_arg_bool, zero_flt) + return None + # 指针: icmp ne x, null + ptr_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cast_arg_bool.Ty, "null") + if ptr_null is not None: + return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, ptr_null) + return None + return None + return None + + def _tc_h4_type_casts(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """t.XXX / typedef 类型转换(未命中返回 None)""" + # 检测 t.XXX 类型转换: t.CUInt64T(ptr), t.CPtr(val), t.CInt(val) 等 + # 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用) + # 支持: + # 单参数: t.CInt(val) → 目标类型 = map_t_type(func_name) + # 双参数: t.CInt(val, t.CPtr) → 目标类型 = Ptr(map_t_type(func_name)) + # t 是内部库,一旦确认为类型转换,绝不跌落到跨模块调用 FATAL 路径 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + tc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name: + tc_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_at.value) + if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0: + target_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name) + if target_ty is not None: + tc_effective_can: t.CSizeT = can + # 双参数形式: t.CInt(val, t.CPtr) → Ptr(target_ty) + # 注意: void* 在 LLVM 中非法,CVoid* 应表示为 i8* + if can == 2: + tc_arg2_node: ast.AST | t.CPtr = cargs.get(1) + tc_arg2_is_cptr: int = 0 + if tc_arg2_node is not None: + # 形式 1: t.CPtr(Attribute 形式) + if tc_arg2_node.kind() == ast.ASTKind.Attribute: + tc_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tc_arg2_node) + if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0: + if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name: + tc_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_at.value) + if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0: + tc_arg2_is_cptr = 1 + # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用,如 t.CVoid(x, CPtr)) + elif tc_arg2_node.kind() == ast.ASTKind.Name: + tc_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_node) + if tc_arg2_bn.id is not None and string.strcmp(tc_arg2_bn.id, "CPtr") == 0: + tc_arg2_is_cptr = 1 + if tc_arg2_is_cptr != 0: + # CVoid* → i8*(LLVM 中 void* 表示为 i8*) + match target_ty: + case llvmlite.LLVMType.Void(): + target_ty = llvmlite.Int8(pool) + case _: + pass + target_ty = llvmlite.Ptr(pool, target_ty) + tc_effective_can = 1 + if tc_effective_can == 1: + tc_arg_node: ast.AST | t.CPtr = cargs.get(0) + if tc_arg_node is not None: + 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 HandlesExprCall._translate_t_type_cast( + pool, builder, tc_arg_val, target_ty, + func_name, tc_arg_node, trans) + # t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL + return None + + # 模块限定 typedef 转换: posix.mode_t(mode), w32.win32base.HANDLE(v) 等 + # func = Attribute(value=Name(模块), attr=typedef名),此前被误当跨模块函数调用 + # → "跨模块函数 'sha1.mode_t' 返回类型无法精确获取"(SysLibTest os/_posix.vp + # L130 posix.mode_t(mode) 根因)。typedef 名做类型转换(与裸名 BYTEPTR(x) + # 对齐);非 typedef 名继续走模块函数调用。 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + mt_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if mt_at.value is not None and mt_at.value.kind() == ast.ASTKind.Name: + mt_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(mt_at.value) + if mt_mod_nm.id is not None and string.strcmp(mt_mod_nm.id, "t") != 0 \ + and string.strcmp(mt_mod_nm.id, "c") != 0: + mod_td_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type( + pool, func_name) + if mod_td_ty is None: + mod_td_str: str = HandlesType.lookup_ctypedef(func_name) + if mod_td_str is not None and HandlesType.is_ctypedef_found() != 0: + mod_td_ast: ast.AST | t.CPtr = HandlesType._parse_type_string( + pool, mod_td_str, 0) + if mod_td_ast is not None: + mod_imp_td: str = None + mod_fi_td: str = None + if trans is not None: + mod_imp_td = trans._imported_modules + mod_fi_td = trans._from_imports + mod_td_ty = HandlesType.resolve_annotation_type( + pool, mod_td_ast, mod_imp_td, mod_fi_td, trans) + if mod_td_ty is not None and can == 1: + 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 HandlesExprCall._translate_t_type_cast( + pool, builder, mt_arg_val, mod_td_ty, + func_name, cargs.get(0), trans) + + # 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等 + # 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换 + # map_t_type 包含所有内置 typedef 名称(BYTEPTR/HANDLE/LPCSTR/size_t 等) + # 泛型类型参数转换: 泛型上下文(类特化/泛型函数)中 T(x) → 先解析 T 为具体 + # 类型名(如 "int")再走 map_t_type(Box[int].__init__ 的 self.value = T(v)、 + # combine[T1,T2] 的 T1(b) 依赖此路径) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + bare_fn_name: str = HandlesType.resolve_generic_type_name(func_name) + bare_ty: llvmlite.LLVMType | t.CPtr = None + # 泛型上下文解析出的内建名(如 T→"double"/"float"):map_t_type 只认 t.CDouble, + # 且 float 必须映射 t.CFloat(f32)而非 f64(与注解语义一致) + if string.strcmp(bare_fn_name, "double") == 0: + bare_ty = llvmlite.Double(pool) + elif string.strcmp(bare_fn_name, "float") == 0: + bare_ty = llvmlite.Float(pool) + else: + bare_ty = HandlesType.map_t_type(pool, bare_fn_name) + # 泛型上下文替换出的类型名(如 T→"t.CInt")map_t_type 不识别(只认无前缀名), + # 回退用 resolve_annotation_type 解析(支持 t.CXxx / 结构体类名 / 别名等)。 + # GenericTest4 Box[t.CInt].__init__ 的 self.value = T(v) 依赖此路径。 + if bare_ty is None and string.strcmp(bare_fn_name, func_name) != 0: + gp_ast: ast.AST | t.CPtr = HandlesType._parse_type_string(pool, bare_fn_name, 0) + if gp_ast is not None: + imp_gp: str = None + fi_gp: str = None + if trans is not None: + imp_gp = trans._imported_modules + fi_gp = trans._from_imports + bare_ty = HandlesType.resolve_annotation_type( + pool, gp_ast, imp_gp, fi_gp, trans) + # 泛型类型参数双参数形式: T(val, t.CPtr) → Ptr(T) + # (与 t.CInt(val, t.CPtr) → Ptr(i32) 对齐;vector.vp get() 的 + # typed_ptr = T(offset, t.CPtr) 依赖此路径,否则双参数不进 + # can==1 单参数分支 → 跌落到"裸名调用未定义"误报) + if bare_ty is not None and can == 2: + bare_arg2_node: ast.AST | t.CPtr = cargs.get(1) + bare_arg2_is_cptr: int = 0 + if bare_arg2_node is not None: + # 形式 1: t.CPtr(Attribute 形式) + if bare_arg2_node.kind() == ast.ASTKind.Attribute: + bare_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(bare_arg2_node) + if bare_arg2_at.attr is not None and string.strcmp(bare_arg2_at.attr, "CPtr") == 0: + if bare_arg2_at.value is not None and bare_arg2_at.value.kind() == ast.ASTKind.Name: + bare_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_at.value) + if bare_arg2_nm.id is not None and string.strcmp(bare_arg2_nm.id, "t") == 0: + bare_arg2_is_cptr = 1 + # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用) + elif bare_arg2_node.kind() == ast.ASTKind.Name: + bare_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_node) + if bare_arg2_bn.id is not None and string.strcmp(bare_arg2_bn.id, "CPtr") == 0: + bare_arg2_is_cptr = 1 + if bare_arg2_is_cptr != 0: + # CVoid* → i8*(LLVM 中 void* 表示为 i8*) + match bare_ty: + case llvmlite.LLVMType.Void(): + bare_ty = llvmlite.Int8(pool) + case _: + pass + bare_ty = llvmlite.Ptr(pool, bare_ty) + bare_arg_node: ast.AST | t.CPtr = cargs.get(0) + if bare_arg_node is not None: + 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 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: + bare_arg_node: ast.AST | t.CPtr = cargs.get(0) + if bare_arg_node is not None: + 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 HandlesExprCall._translate_t_type_cast( + pool, builder, bare_arg_val, bare_ty, + bare_fn_name, bare_arg_node, trans) + + return None + + def _tc_h5_sizeof_len_isinst(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """__sizeof__/len/isinstance 内置(未命中返回 None)""" + # 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64) + # __sizeof__ 是内置方法,不走跨模块调用路径 + # 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__() + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + sz_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0: + if sz_at.value is not None and can == 0: + sz_cls_name: str = None + sz_vk: int = sz_at.value.kind() + if sz_vk == ast.ASTKind.Name: + sz_cls_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sz_at.value) + sz_cls_name = sz_cls_nm2.id + elif sz_vk == ast.ASTKind.Attribute: + sz_inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sz_at.value) + sz_cls_name = sz_inner_at.attr + # 最终解析出的结构体类型:类型名命中 → 泛型特化(Stack[T])→ 实例接收者类型(self/obj) + sz_resolved_ty: llvmlite.LLVMType | t.CPtr = None + sz_resolved_name: str = sz_cls_name + if sz_cls_name is not None: + # 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__() + sz_cls_name = HandlesType.resolve_generic_type_name(sz_cls_name) + sz_resolved_name = sz_cls_name + # 去除模块前缀: Viper 解析器将 t.CInt 解析为 Name(id="t.CInt") + # 而非 Attribute(value=Name("t"), attr="CInt"),需要手动提取最后的类名分量 + # "t.CInt" → "CInt", "w32.win32file.WIN32_FIND_DATAA" → "WIN32_FIND_DATAA" + dot_pos: str = string.strrchr(sz_cls_name, '.') + if dot_pos is not None: + sz_cls_name = dot_pos + 1 + # 联合类型(如 AST|t.CPtr)按指针大小处理(8 字节) + # 联合类型在 TPV 中表示指针,可以指向多种类型 + # 对应 TPC 中对 BinOp/BitOr 联合类型的特殊处理 + if string.strstr(sz_cls_name, "|") is not None: + return llvmlite.const_int64(pool, 8) + # 内置类型 sizeof(int=4, str/bytes=8 指针, double=8 等) + sz_builtin: int = -1 + if string.strcmp(sz_cls_name, "int") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "str") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "bytes") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CInt") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CInt8T") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "CInt16T") == 0: + sz_builtin = 2 + elif string.strcmp(sz_cls_name, "CInt32T") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CInt64T") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CChar") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "CDouble") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CFloat") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "CPtr") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CSizeT") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "CBool") == 0: + sz_builtin = 1 + elif string.strcmp(sz_cls_name, "bool") == 0: + sz_builtin = 1 + # 泛型 T 解析出的裸内建名(resolve_generic_type_name 返回 + # _infer_generic_ctor_type_arg 的输出,如 T→"double"/"float"): + # 缺省会让 sz_builtin=-1 → 落到"回退 2"把 Name(T) 当值翻译 → + # NameError(VectorGenericTest Vector[double].__init__ 回归根因) + elif string.strcmp(sz_cls_name, "double") == 0: + sz_builtin = 8 + elif string.strcmp(sz_cls_name, "float") == 0: + sz_builtin = 4 + elif string.strcmp(sz_cls_name, "char") == 0: + sz_builtin = 1 + if sz_builtin >= 0: + # 注意: 必须用 const_int64 而非 ConstInt(...,"0") + # ConstInt 的 name 参数是 IR 文本表示,ValuePrint 输出时使用 Name 而非 IntVal + # 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值 + return llvmlite.const_int64(pool, sz_builtin) + sz_resolved_ty = HandlesStruct.get_struct_type(sz_cls_name) + # 回退 1: 泛型类引用接收者 Stack[T].__sizeof__() — Subscript → 特化后计算大小 + # (GenericTest2 Stack.type_size 依赖此路径) + if sz_resolved_ty is None and trans is not None and sz_vk == ast.ASTKind.Subscript: + sub_sz: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sz_at.value) + 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 = 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: + gai_sz: t.CSizeT = len(gen_args_sz) + gai2_sz: t.CSizeT = 0 + for gai2_sz in range(gai_sz): + gres_sz: str = HandlesType.resolve_generic_type_name( + gen_args_sz.get(gai2_sz)) + gargs_resolved.append(gres_sz) + spec_sz: str = HandlesClassDef._specialize_generic_class( + trans, gen_nm_sz.id, gargs_resolved) + if spec_sz is not None: + sz_resolved_name = spec_sz + sz_resolved_ty = HandlesStruct.get_struct_type(spec_sz) + # 回退 2: 实例接收者 self.__sizeof__() / obj.__sizeof__() — 用接收者值的实际类型 + # (GenericTest2 Stack.size_of 依赖此路径;self 在方法内是 Ptr(Stack[int])) + # 数组变量接收者 bl_count.__sizeof__()(t.CArray[T, N] 变量)→ alloca + # 指针 Ptr([N x T]),算 N*elem_size(TPC _HandleSizeofLlvm 数组分支; + # zhuff.vp memset(bl_count, 0, bl_count.__sizeof__()) 依赖) + if sz_resolved_ty is None: + inst_sz_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, sz_at.value, None, 0, trans) + if inst_sz_val is not None and inst_sz_val.Ty is not None: + match inst_sz_val.Ty: + case llvmlite.LLVMType.Ptr(inst_inner_sz): + match inst_inner_sz: + case llvmlite.LLVMType.Struct(_, _, _): + sz_resolved_ty = inst_inner_sz + case llvmlite.LLVMType.Array(_, _): + sz_resolved_ty = inst_inner_sz + case _: + pass + case llvmlite.LLVMType.Struct(_, _, _): + sz_resolved_ty = inst_sz_val.Ty + case llvmlite.LLVMType.Array(_, _): + # 全局数组变量(模块级 t.CArray[T,N])translate_value + # 返回数组值 [N x T](非指针);局部数组返回 alloca + # 指针 Ptr([N x T]) 走上方 Ptr(Array) 分支。 + # pyzlib_error_msg.__sizeof__() 依赖(全局字符缓冲)。 + sz_resolved_ty = inst_sz_val.Ty + case _: + pass + if sz_resolved_ty is not None: + sz_val: int = HandlesClassDef._get_type_size(sz_resolved_ty) + if sz_val > 0: + return llvmlite.const_int64(pool, sz_val) + # 类型已注册但大小为 0(opaque struct 或字段链表未填充):Python 风格报错终止 + HandlesType.fatal_error( + sz_at, f"类型 '{sz_resolved_name}' 已注册但大小为 0(字段链表未填充),无法计算大小", + "TypeError") + # 类型未注册:Python 风格报错终止,不静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出) + if sz_resolved_name is None: + sz_resolved_name = "(unknown)" + HandlesType.fatal_error( + sz_at, f"类型 '{sz_resolved_name}' 未在结构体表中注册,无法计算大小", + "TypeError") + + # 检测 len(obj) — 返回 list 对象的 __count__ 字段(偏移 8,i64) + # __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct + # 注意: 必须用 translate_value 而非 translate_name_value,因为 len_at.value + # 可能是 Attribute 节点(如 md_ags.args),translate_name_value 只处理 Name 节点, + # 对 Attribute 会错误返回 i32 0,导致 GEP base 不是指针(base of getelementptr must be a pointer) + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + len_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0: + if len_at.value is not None and can == 0: + obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, len_at.value, funcs_ptr, func_count, trans) + if obj_val is not None and obj_val.Ty is not None: + # 防御性类型检查: obj_val 必须是指针类型才能做 GEP + # 如果 translate_value 返回 i32 (如 CDefine 常量被误解析、 + # 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针, + # 导致 llc 报错 "base of getelementptr must be a pointer" + if HandlesExpr.is_ptr_type(obj_val.Ty) == 0: + # 类型推断失败(非指针/结构体):fail-fast,绝不返回 0 掩盖错误 + HandlesType.fatal_error( + len_at.value, "len() 参数类型推断失败(非指针/结构体)", "TypeError") + i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + # 注意: 必须用 const_int64 而非 ConstInt(...,"0") + # ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0 + # 导致 GEP 索引为 0(访问 __data__)而非 1(访问 __count__) + idx_one: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + count_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( + builder, i64_ty_len, obj_val, idx_one) + if count_ptr is not None: + return llvmlite.build_load(builder, i64_ty_len, count_ptr) + + # 检测 len() 内置函数调用 — 结构体对象走 __len__ 方法,字符串走 strlen + # len(s) 对 str 类型调用 strlen,返回 i64 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + if func_name is not None and string.strcmp(func_name, "len") == 0: + if can == 1: + len_arg_node: ast.AST | t.CPtr = cargs.get(0) + if len_arg_node is not None: + len_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, len_arg_node, None, 0, trans) + if len_val is not None: + # len(数组):t.CArray[T, N] → 常量 N(对齐 TPC + # _HandleLenLlvm 的 ArrayType.count 分支)。数组变量 + # translate_value 可能返回 Ptr([N x T])(alloca 指针) + # 或 [N x T] 值,两种都识别;否则会误走 strlen 把 + # 数组首元素当字符串读 → 垃圾长度。 + len_is_arr: int = 0 + len_arr_n: int = 0 + if len_val.Ty is not None: + if HandlesExpr.is_ptr_type(len_val.Ty) != 0: + len_ap: llvmlite.LLVMType | t.CPtr = len_val.Ty.Pointee + if len_ap is not None: + match len_ap: + case llvmlite.LLVMType.Array(_, len_arr_cnt): + len_is_arr = 1 + len_arr_n = len_arr_cnt + case _: + pass + else: + match len_val.Ty: + case llvmlite.LLVMType.Array(_, len_arr_cnt): + len_is_arr = 1 + len_arr_n = len_arr_cnt + case _: + pass + if len_is_arr != 0: + return llvmlite.const_int64(pool, len_arr_n) + # len(对象):有 __len__ 就调用,没有就编译期报错 + # (用户要求 2026-08-15,不再静默 strlen 读对象首字段): + # - list 泛型内置容器:__len__ 由 list 内置分支内联 + # (读 __count__,偏移 1),不生成方法函数 + # (_is_list_builtin_method,通用判断非特判) + # - 普通类:调用 {Class}.__len__ 函数 + # - 都没有:fatal_error + # str(Ptr(Int8))保持 strlen(内建语义)。 + len_struct_ty: llvmlite.LLVMType | t.CPtr = \ + HandlesStruct.get_struct_type_from_value(len_val) + if len_struct_ty is not None: + len_cls_nm: str = HandlesStruct.get_class_name_by_type( + pool, len_struct_ty) + if len_cls_nm is None: + HandlesType.fatal_error( + len_arg_node, "len() 参数类型推断失败(结构体类名未知)", + "TypeError") + # list 内置 __len__:读 __count__(GEP 偏移 1,i64) + 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( + builder, i64_ty_lb, len_val, idx_one_lb) + if cnt_ptr_lb is not None: + return llvmlite.build_load(builder, i64_ty_lb, cnt_ptr_lb) + len_lookup: str = pool.alloc(128) + if len_lookup is not None: + viperlib.snprintf(len_lookup, 128, "%s.__len__", len_cls_nm) + len_fn2: llvmlite.Function | t.CPtr = self.find_func_in_module( + mod, len_lookup) + if len_fn2 is not None: + len_ret_ty2: llvmlite.LLVMType | t.CPtr = \ + llvmlite.function_get_ret_ty(len_fn2) + len_fn_name2: str = \ + llvmlite.function_get_name(len_fn2) + if len_ret_ty2 is not None and len_fn_name2 is not None: + # self 参数类型对齐(按方法首个形参 bitcast) + len_self_arg2: llvmlite.Value | t.CPtr = len_val + len_first_param2: llvmlite.Param | t.CPtr = \ + llvmlite.function_get_param_head(len_fn2) + if len_first_param2 is not None: + len_self_ty2: llvmlite.LLVMType | t.CPtr = \ + llvmlite.param_get_ty(len_first_param2) + if len_self_ty2 is not None and len_val.Ty is not None: + len_self_arg2 = llvmlite.build_bitcast( + builder, len_val, len_self_ty2) + len_self_arg2.Next = None + return llvmlite.build_call( + builder, len_fn_name2, len_self_arg2, + 1, len_ret_ty2, 0) + # len_fn2 未命中(跨模块方法):如 ndarray[t.CDouble].__len__ + # 定义在 numpy——泛型特化方法无 stub declare,find_func_in_module + # 后缀匹配查不到。用结构体所属模块 sha1 构造 + # {sha1}.{cls}.__len__ 精确调用名(对齐 _translate_method_call + # 跨模块调用名构造),返回类型从 text.ll/vpi 精确解析, + # _ensure_method_declare 建 declare 后调用。 + len_cls_sha1_x: str = HandlesStruct.get_struct_sha1(len_cls_nm) + if len_cls_sha1_x is not None: + # 缓冲区需容纳 "{sha1}.{cls}.__len__": + # 2 个点 + "__len__"(7) + NUL = 10;+8 会截断 + # 末两位 → 符号变 ".__len" 链接 undefined + # (NumpyTest test_len 链接错误根因) + len_ml_x: t.CSizeT = string.strlen(len_cls_sha1_x) \ + + string.strlen(len_cls_nm) + 10 + len_mangled_x: str = pool.alloc(len_ml_x) + if len_mangled_x is not None: + viperlib.snprintf(len_mangled_x, len_ml_x, + "%s.%s.__len__", len_cls_sha1_x, len_cls_nm) + len_ret_x: llvmlite.LLVMType | t.CPtr = \ + self._LookupMethodRetTyFromTextLL( + pool, len_cls_sha1_x, len_cls_nm, "__len__") + if len_ret_x is None: + len_ret_x = self._lookup_method_ret_ty_via_vpi( + pool, len_cls_sha1_x, len_cls_nm, "__len__") + if len_ret_x is not None: + # self 参数按对象实际类型 Ptr(len_struct_ty)(与定义侧 + # 同名类型链接匹配);len_val 已是 load 后的对象指针。 + # Value 链直接作 param_head(同跨模块调用模式)。 + len_self_x: llvmlite.Value | t.CPtr = len_val + len_self_x.Next = None + self._ensure_method_declare( + pool, mod, len_mangled_x, len_ret_x, + len_self_x, 1) + return llvmlite.build_call( + builder, len_mangled_x, len_self_x, + 1, len_ret_x, 0) + # fail-fast:类没有 __len__(用户要求编译期报错) + HandlesType.fatal_error( + len_arg_node, + f"len() 参数类型 '{len_cls_nm}' 没有 __len__ 方法", + "TypeError") + # 非结构体:str(Ptr(Int8))走 strlen;其它类型 fail-fast + len_arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(len_val) + len_is_str: int = 0 + if len_arg_ty is not None and HandlesExpr.is_ptr_type(len_arg_ty) != 0: + match len_arg_ty: + case llvmlite.LLVMType.Ptr(len_pt_ty): + if len_pt_ty is not None: + match len_pt_ty: + case llvmlite.LLVMType.Int(len_pt_bits): + if len_pt_bits == 8: + len_is_str = 1 + case _: + pass + case _: + pass + if len_is_str != 0: + # 确保 strlen 在模块中有声明 + strlen_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, "strlen") + if strlen_fn is None: + i64_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ptr_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + strlen_fn = llvmlite.create_declare(pool, mod, "strlen", i64_ty_ln) + if strlen_fn is not None: + llvmlite.add_param(pool, strlen_fn, i8_ptr_ty_ln, "s") + # 参数类型转换为 i8* + i8_ptr_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + len_coerced: llvmlite.Value | t.CPtr = len_val + if HandlesExpr.is_ptr_type(len_arg_ty) != 0: + len_coerced = llvmlite.build_bitcast(builder, len_val, i8_ptr_ty_ln2) + # 构建单参数链表并调用 strlen + len_coerced.Next = None + i64_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0) + # fail-fast:非字符串/数组/对象,无法求长度 + HandlesType.fatal_error( + len_arg_node, "len() 参数类型不支持(非字符串/数组/对象)", + "TypeError") + + # 检测 isinstance() 内置函数调用 — 运行时 vtable 子类集合比较 + # isinstance(obj, Cls):obj 头部 vtable 指针 ∈ {Cls 及全部子类 vtable}; + # NoVTable 目标类回退编译时静态判断(详见 _translate_isinstance)。 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + if func_name is not None and string.strcmp(func_name, "isinstance") == 0: + if can >= 2: + is_res: llvmlite.Value | t.CPtr = HandlesExprCall._translate_isinstance( + pool, builder, mod, cargs.get(0), cargs.get(1), trans) + if is_res is not None: + return is_res + + return None + + def _tc_h6_method_dispatch(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """静态类/方法调用/表达式接收者/self.field/list 内置(未命中返回 None)""" + # 检测类名静态/类方法调用: ClassName.method(args) + # 当 cl.func 是 Attribute、value 是已注册结构体类名(非普通变量)时, + # 且方法带 @staticmethod/@classmethod 元数据,走静态调用路径 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + st_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if st_at is not None and st_at.value is not None and trans is not None: + if st_at.value.kind() == ast.ASTKind.Name: + st_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(st_at.value) + if st_nm.id is not None: + # 仅当该名称不是普通变量且是已注册结构体类名时尝试静态/类方法 + # 追加"非导入模块"条件:st_nm.id 是模块名(import X as Y 把别名 + # Y 加入 _imported_modules,HandlesImports L344-347)时,X.Y(...) + # 是模块限定调用(Module.Class 构造 / Module.func 函数),不是 + # ClassName.method(obj,args)。模块名与类名同名时(CompilerFactory. + # CompilerFactory(...) 构造 / .set_factory(...) 函数,main.vp + # 追加84/84b 根因)get_struct_type(st_nm.id) 会误判为类名 → + # 把首实参当 self 传 _call_method_on_ptr → 返回类型查 "X.Y" 永远 + # 落空 → fail-fast。模块限定调用由尾部 ctor 检测(L7441 模块限定 + # 构造)与跨模块函数路径正确路由。 + st_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, st_nm.id) + if st_var is None and HandlesStruct.get_struct_type(st_nm.id) is not None \ + and HandlesImports.is_module_imported( + trans._imported_modules, st_nm.id) == 0: + # REnum 变体构造优先于静态/类方法调用: + # ClassName.VariantName(args)(如 Option.Some(42))若被当 + # "实例方法经类名调用"处理,会把首实参 42 当 self 传 + # _call_method_on_ptr → 查 "Option.Some" 方法返回类型 → + # 跨模块 stub 未命中 → fail-fast(EnumTest "方法 + # 'Option.Some' 返回类型无法确定" 根因)。REnum 变体 + # 构造检测原在 translate_call 尾部(L7493),被本分支 + # 拦截先执行不到,此处提前检测。 + if HandlesClassDef._is_renum_class_name(st_nm.id) != 0: + rc_tag_sc: int = HandlesClassDef._lookup_renum_variant_in_class( + st_nm.id, func_name) + if rc_tag_sc >= 0: + 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 = HandlesExprCall._translate_static_class_call( + pool, builder, mod, st_nm.id, func_name, cl, trans) + if st_res is not None: + return st_res + # 实例方法经类名调用: ClassName.method(obj, args) → obj.method(args) + # (Python 语义,首参是 self 对象;zdeflate.vp + # zdeflate_stream.find_match(s, data, ...) 根因:_translate_ + # static_class_call 对非静态方法返回 None 后,ClassName 被 + # 通用路径当模块名 → "跨模块调用找不到模块 SHA1") + # st_nm.id == func_name(类名==方法名,如 CompilerFactory. + # CompilerFactory(...))不是实例方法调用而是构造调用: + # 模块名与类名同名时本分支把模块限定类构造误判为 + # ClassName.method(obj,args),首实参当 self 传 → + # _call_method_on_ptr 查 "X.X" 返回类型永远落空 → + # fail-fast(main.vp CompilerFactory 追加84 根因)。 + # 跳过本分支,落到 translate_call 尾部的 ctor 检测 + # (L7426 模块限定类构造 find_struct_by_module 正确路由)。 + if can >= 1 and cargs is not None \ + and string.strcmp(st_nm.id, func_name) != 0: + im_self: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, cargs.get(0), None, 0, trans) + if im_self is not None: + im_rem: t.CSizeT | t.CPtr = None + if can >= 2: + im_rem = pool.alloc(t.CSizeT(can - 1) * 8) + if im_rem is not None: + ri_im: t.CSizeT + for ri_im in range(can - 1): + im_rv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + 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 = 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: + return im_res + elif st_at.value.kind() == ast.ASTKind.Attribute: + # 模块限定静态调用: module.ClassName.static_method(args) + # cl.func = Attribute(value=Attribute(value=Name(module), + # attr=ClassName), attr=method_name) + # 此前未检测 → 走通用路径把 method_name 当裸函数解析, + # 生成 call i32 @from_long(无类名/SHA1 前缀)→ 链接 + # undefined reference(CPythonTest PyLongObj.from_long 根因) + st_at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(st_at.value) + if st_at2 is not None and st_at2.attr is not None and st_at2.value is not None: + 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 = HandlesExprCall._translate_static_class_call( + pool, builder, mod, st_at2.attr, func_name, cl, trans) + if st_res2 is not None: + return st_res2 + + # 检测方法调用: obj.method(args) + # 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if method_at is not None and method_at.value is not None: + if method_at.value.kind() == ast.ASTKind.Name and trans is not None: + method_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(method_at.value) + if method_obj_nm.id is not None: + # 查找对象变量 + obj_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, method_obj_nm.id) + if obj_var is not None and obj_var.Ty is not None: + # 检查是否为 Ptr(Struct(...))(结构体值变量) + # 或 Ptr(Ptr(Struct(...)))(指针变量,需 load) + match obj_var.Ty: + case llvmlite.LLVMType.Ptr(obj_struct_ty): + class_nm: str = HandlesStruct.get_class_name_by_type( + pool, obj_struct_ty) + if class_nm is not None: + # list 泛型内置容器方法(append/get/set/pop/clear/__iter__/ + # __len__/__getitem__/__setitem__)由下方 list 内置分支 + # (L5848 起)内联 GEP 处理,不注册方法函数;若走 + # _translate_method_call 会查 append 返回类型(函数/text.ll/ + # vpi stub 均未命中)→ fail-fast。检测到 list 方法时 + # 跳过 method_call,落到内置分支(NewAstTest body.append 根因)。 + 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)) + # load 获取实际指针 Ptr(Struct) 后再查找 + match obj_struct_ty: + case llvmlite.LLVMType.Ptr(inner_struct_ty): + inner_nm: str = HandlesStruct.get_class_name_by_type( + pool, inner_struct_ty) + if inner_nm is not None: + # list 内置方法同样跳过(同 Ptr(Struct) 分支) + 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 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 = HandlesExprCall._translate_fakeduck_call( + pool, builder, mod, None, func_name, cl, trans) + if fd_name_res is not None: + return fd_name_res + # AnnotClassName 回退:联合类型简化为 Ptr(i8) 时, + # 通过原始类型注解的类名查找结构体 + var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( + trans.SymTab, method_obj_nm.id) + if var_entry is not None and var_entry.AnnotClassName is not None: + annot_val: str = var_entry.AnnotClassName + # 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy" + dot_ptr: str = string.strrchr(annot_val, '.') + cls_nm2: str = annot_val + mod_nm2: str = None + if dot_ptr is not None: + cls_nm2 = dot_ptr + 1 + total_len_av: t.CSizeT = string.strlen(annot_val) + cls_len_av: t.CSizeT = string.strlen(cls_nm2) + mod_len2: t.CSizeT = total_len_av - cls_len_av - 1 + mod_nm2 = pool.alloc(mod_len2 + 1) + if mod_nm2 is not None: + string.strncpy(mod_nm2, annot_val, mod_len2) + mod_nm2[mod_len2] = '\0' + # 检查结构体是否已注册 + if HandlesStruct.get_struct_type(cls_nm2) is not None: + # list 内置方法跳过 method_call(同 Ptr(Struct) 分支), + # 落到下方 list 内置分支 + 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 HandlesExprCall._translate_method_call( + pool, builder, mod, cls_nm2, func_name, + obj_ptr2, cl, trans) + else: + # list 内置方法跳过(结构体未注册路径同样不能 + # 构造 {sha1}.{cls}.append 调用名——list 方法无此函数) + 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 = HandlesExprCall._translate_fakeduck_call( + pool, builder, mod, cls_nm2, func_name, cl, trans) + if fd_res is not None: + return fd_res + # 结构体未注册(跨模块依赖未翻译): + # 用模块名查 SHA1 构造方法调用名 + sha1_fc: str = None + if mod_nm2 is not None: + sha1_fc = self._lookup_module_sha1(mod_nm2) + if sha1_fc is not None: + # 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名 + mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3 + mangled3: str = pool.alloc(mlen3) + if mangled3 is not None: + viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name) + # load obj_ptr (self) + i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load( + builder, i8_ptr_ty3, obj_var) + if obj_ptr3 is not None: + # 构建参数链表: obj_ptr3 (self) → 其他参数 + llvmlite.value_set_next(obj_ptr3, None) + head3: llvmlite.Value | t.CPtr = obj_ptr3 + tail3: llvmlite.Value | t.CPtr = obj_ptr3 + for ai3 in range(can): + arg3: ast.AST | t.CPtr = cargs.get(ai3) + if arg3 is not None: + arg_val3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, arg3, None, 0, trans) + if arg_val3 is not None: + llvmlite.value_set_next(arg_val3, None) + llvmlite.value_set_next(tail3, arg_val3) + tail3 = arg_val3 + total3: int = 1 + can + ret_ty3: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty( + pool, cls_nm2, func_name) + if ret_ty3 is None: + ret_ty3 = self._LookupMethodRetTyFromTextLL( + pool, sha1_fc, cls_nm2, func_name) + if ret_ty3 is None: + # 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单) + ret_ty3 = self._lookup_method_ret_ty_via_vpi( + pool, sha1_fc, cls_nm2, func_name) + if ret_ty3 is None: + # 本分支仅在"注解类结构体未注册"时到达(L6932 else): + # 类未注册 → 无法沿 MRO 解析 Mixin 方法定义模块。 + # 例如 g 注解 Generator.Generator,但 _register_cdefine_from_value + # 定义在 AssignGenMixin.vp——其 text.ll 的 define 名是 + # {AssignGenMixin_sha1}.AssignGenMixin.xxx,查 + # {Generator_sha1}.Generator.xxx 永远落空(追加80d 根因; + # sha1_fc 存在 + text.ll 存在仍查不到,固定 256KB 截断 + # 只是次要因素)。必须标记 pending:等 Generator 注册后 + # 下遍走 L6919 已注册分支 → _translate_method_call 沿 + # MRO 链找到 AssignGenMixin → 精确解析。真正不存在的 + # 类/方法由 Phase A 收敛检查兜底,绝不在此 fail-fast + # 中断多遍收敛(对齐追加77/77b 类 defer 原则)。 + if trans is not None: + trans._deps_pending = 1 + ret_ty3 = llvmlite.Void(pool) + self._ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3) + return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0) + + # ============================================================ + # 检测表达式接收者方法调用: (expr).method(args) + # + # 当 method_at.value 是 BinOp/Subscript/Call 等非 Name/Attribute 表达式时 + # (如 (a + b).dot(c)、(v1 + v2) * 3.0),先 translate_value 求值接收者, + # 再从值的 LLVM 类型(Ptr(Struct))解析类名,走方法调用路径。 + # ============================================================ + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + expr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if expr_method_at is not None and expr_method_at.value is not None and trans is not None: + evk: int = expr_method_at.value.kind() + # Attribute 接收者区分两种形态: + # 1. 模块限定路径(os._win32.exists / w32.fileio.fn)——根名是已导入 + # 模块或 t/c,留给下方跨模块限定路径处理 + # 2. 字段链表达式接收者(self.writer.write_bits / self.pool.alloc) + # ——根名是对象(self/局部变量),必须走本方法调用路径; + # 否则被模块限定路径误判 xmod_path="self.writer" → "找不到模块 + # SHA1"(zdeflate.vp write_fixed_block 根因) + is_mod_path_expr: int = 0 + if evk == ast.ASTKind.Attribute: + expr_root: ast.AST | t.CPtr = expr_method_at.value + while expr_root is not None and expr_root.kind() == ast.ASTKind.Attribute: + expr_root = (ast.Attribute | t.CPtr)(expr_root).value + if expr_root is not None and expr_root.kind() == ast.ASTKind.Name: + expr_root_nm: str = (ast.Name | t.CPtr)(expr_root).id + if expr_root_nm is not None: + if string.strcmp(expr_root_nm, "t") == 0 or \ + string.strcmp(expr_root_nm, "c") == 0: + is_mod_path_expr = 1 + elif trans._imported_modules is not None: + if HandlesImports.is_module_imported( + trans._imported_modules, expr_root_nm) != 0: + is_mod_path_expr = 1 + if evk != ast.ASTKind.Name and is_mod_path_expr == 0: + # 翻译接收者表达式(求值结果应为 Ptr(Struct)) + expr_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans) + if expr_obj is not None and expr_obj.Ty is not None: + expr_cls_nm: str = None + # 递归解 Ptr:识别 X|t.CPtr 联合简化的 Ptr(Ptr(Struct)) + # (如 (a*2.0 - b) 中 __mul__ 返回 Vec3**),否则方法 + # 调用被当裸函数 @dot 解析 → 链接 undefined symbol + expr_struct_ty: llvmlite.LLVMType | t.CPtr = \ + HandlesStruct.get_struct_type_from_value(expr_obj) + if expr_struct_ty is not None: + expr_cls_nm = HandlesStruct.get_class_name_by_type( + pool, expr_struct_ty) + # 回退:LLVM 类型为 Ptr(i8)(方法返回 X|t.CPtr 无类型信息)时, + # 从接收者表达式结构推断类名(链式调用 c2.scale(2.0).move(...) + # 的 scale 返回 Ptr(i8),经 infer_expr_class → vpi 返回注解) + # 跨 Mixin 不能 self 调用 ExprGenMixin 方法,经全局单例 + if expr_cls_nm is None: + import lib.core.Gen.Generator as Generator + g3: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( + t.CVoid(HandlesExpr._g_gen, t.CPtr)) + if g3 is not None: + expr_cls_nm = g3.infer_expr_class( + pool, mod, expr_method_at.value, trans) + if expr_cls_nm is not None: + # 值类型接收者(内嵌 struct 字段,如 zdeflate s.writer 值字段): + # 方法调用 self 必须传字段地址(GEP)而非 load 出的结构体值, + # 否则结构体值(40B)塞进 zbit_writer* 参数 → ABI 错配 → + # 被调方把值当 this 指针解引用 → GEP 0x18 崩溃 + # (s.writer.write_zlib_header 运行时 access-violation 根因; + # 本路径 evk=Attribute 先于 self.field.method() 分支命中)。 + expr_is_ptr: int = 0 + match expr_obj.Ty: + case llvmlite.LLVMType.Ptr(expr_ptr_inner): + expr_is_ptr = 1 + case _: + expr_is_ptr = 0 + if expr_is_ptr == 0: + expr_addr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( + builder, pool, mod, expr_method_at.value, trans) + if expr_addr is not None: + expr_obj = expr_addr + 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 = HandlesExprCall._translate_fakeduck_call( + pool, builder, mod, None, func_name, cl, trans) + if fd_expr_res is not None: + return fd_expr_res + + # ============================================================ + # 检测 self.field.method() 调用 + # + # 当 method_at.value 是 Attribute(字段访问,如 self.__pool__)时, + # 翻译字段值获取对象指针,然后走方法调用路径。 + # + # 路径1: 从字段值的 LLVM 类型获取类名(字段类型为 Ptr(Struct("MemManager"))) + # 路径2: 从字段的 AnnotClassName 回退查找(字段类型被简化为 Ptr(i8) 时) + # ============================================================ + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + attr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if attr_method_at is not None and attr_method_at.value is not None: + if attr_method_at.value.kind() == ast.ASTKind.Attribute and trans is not None: + inner_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_method_at.value) + if inner_attr is not None and inner_attr.attr is not None: + # 翻译 self.__pool__ 获取字段值(已 load 的对象指针) + field_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans) + if field_obj is not None and field_obj.Ty is not None: + field_cls_nm: str = None + # 路径1: 从字段值的 LLVM 类型获取类名 + match field_obj.Ty: + case llvmlite.LLVMType.Ptr(field_struct_ty): + field_cls_nm = HandlesStruct.get_class_name_by_type( + pool, field_struct_ty) + # 路径2: 从字段注解类名回退查找 + if field_cls_nm is None: + if inner_attr.value is not None and inner_attr.value.kind() == ast.ASTKind.Name: + inner_name_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_attr.value) + if inner_name_node is not None and inner_name_node.id is not None: + inner_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( + trans.SymTab, inner_name_node.id) + if inner_var is not None and inner_var.Ty is not None: + match inner_var.Ty: + case llvmlite.LLVMType.Ptr(field_owner_struct_ty): + field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( + field_owner_struct_ty, inner_attr.attr) + if field_info is not None: + field_annot: str = HandlesStruct.get_field_annot_class_name(field_info) + if field_annot is not None: + dot_p: str = string.strrchr(field_annot, 46) + if dot_p is not None: + field_cls_nm = dot_p + 1 + else: + field_cls_nm = field_annot + if field_cls_nm is not None: + # 值类型字段(内嵌 struct,如 zdeflate_stream.writer: zbit_writer) + # 方法调用 self 必须传字段地址(GEP),而非 load 出的结构体值: + # 传值给 stub 声明/define 的 zbit_writer* 参数 → ABI 错配, + # 被调方把结构体值前 8 字节当 this 指针解引用 → GEP 0x18 崩溃 + # (zdeflate s.writer.write_zlib_header 运行时 access-violation 根因)。 + is_val_field: int = 0 + match field_obj.Ty: + case llvmlite.LLVMType.Ptr(field_ptr_inner): + is_val_field = 0 + case _: + is_val_field = 1 + if is_val_field != 0: + field_addr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( + builder, pool, mod, attr_method_at.value, trans) + if field_addr is not None: + field_obj = field_addr + return HandlesExprCall._translate_method_call( + pool, builder, mod, field_cls_nm, func_name, + field_obj, cl, trans) + + # ============================================================ + # 检测 list 内置方法调用: lst.get(i), lst.set(i,v), lst.pop(), lst.clear(), lst.__iter__() + # list[T] 是泛型类不注册 struct,方法调用处理器(上方)无法处理, + # 需要在此特殊处理。 + # list 结构布局 (6 字段 × 8 字节): + # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) + # ============================================================ + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + lm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) + if lm_at is not None and lm_at.attr is not None and lm_at.value is not None: + lm_name: str = lm_at.attr + # 判断是否是 list 方法名 + lm_is_list: int = 0 + if string.strcmp(lm_name, "get") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__getitem__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "set") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__setitem__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "pop") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "clear") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "__iter__") == 0: lm_is_list = 1 + elif string.strcmp(lm_name, "append") == 0: lm_is_list = 1 + + if lm_is_list == 1 and trans is not None: + # 翻译 list 对象 + lm_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans) + if lm_obj is not None: + # 防御性类型检查: lm_obj 必须是指针类型才能做 GEP + # translate_value 对某些 Attribute 节点(如 ast.Arguments 的属性) + # 可能返回 i32 0 (非指针),直接 GEP 会导致 + # "base of getelementptr must be a pointer" 错误 + if lm_obj.Ty is None or HandlesExpr.is_ptr_type(lm_obj.Ty) == 0: + # translate_value 类型推断失败(目标对象非指针): + # fail-fast,绝不 VLogger.critical 后 return None 静默吞掉 + HandlesType.fatal_error( + lm_at.value, f"list 方法 '{lm_name}' 目标对象非指针", "TypeError") + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + # 元素类型 T:从 list 特化类型名解析(list[int]→i32、 + # list[str]→i8*、未知/指针元素→i8*)。此前 get/set/pop + # 固定 i8*(8 字节)读写:set 的 8 字节 store 覆盖相邻元素 + # (inttoptr 值,如 set(1,99) 把 data[8..11] 的 30 清 0), + # pop 读回 0 → ListTest "pop FAILED expect 30" 根因。 + # subscript 路径(list_getitem_inline 调用方)已用 + # _list_elem_type_from_name 修正,方法调用路径漏改。 + lm_esty: llvmlite.LLVMType | t.CPtr = \ + HandlesStruct.get_struct_type_from_value(lm_obj) + lm_ename: str = None + if lm_esty is not None: + lm_ename = llvmlite.get_struct_name(lm_esty) + lm_elem_ty: llvmlite.LLVMType | t.CPtr = None + if lm_ename is not None: + import lib.core.Gen.Generator as Generator + g_le: Generator.Generator | t.CPtr = ( + Generator.Generator | t.CPtr)( + t.CVoid(HandlesExpr._g_gen, t.CPtr)) + if g_le is not None: + lm_elem_ty = g_le._list_elem_type_from_name( + pool, lm_ename) + if lm_elem_ty is None: + lm_elem_ty = i8_ptr_ty + + # get / __getitem__: 返回 index 处的元素 + if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0: + if can >= 1: + # 加载 __data__ (偏移 0) + g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) + g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) + # 加载 __elem_size__ (偏移 32, index 4) + g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) + g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) + # 翻译 index + g_idx_node: ast.AST | t.CPtr = cargs.get(0) + g_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, g_idx_node, None, 0, trans) + if g_data is not None and g_esize is not None and g_idx_val is not None: + g_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, g_idx_val, i64_ty, g_idx_node) + g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) + g_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, g_data, g_offset) + if g_addr is not None: + g_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, g_addr, llvmlite.Ptr(pool, lm_elem_ty)) + if g_ep is not None: + return llvmlite.build_load(builder, lm_elem_ty, g_ep) + + # set / __setitem__: 设置 index 处的元素 + elif string.strcmp(lm_name, "set") == 0 or string.strcmp(lm_name, "__setitem__") == 0: + if can >= 2: + s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) + s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) + s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) + s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) + s_idx_node: ast.AST | t.CPtr = cargs.get(0) + s_val_node: ast.AST | t.CPtr = cargs.get(1) + s_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, s_idx_node, None, 0, trans) + s_val_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, s_val_node, None, 0, trans) + if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None: + s_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, s_idx_val, i64_ty, s_idx_node) + s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) + s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) + if s_addr is not None: + s_val_elem: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( + builder, s_val_val, lm_elem_ty, s_val_node) + s_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, s_addr, llvmlite.Ptr(pool, lm_elem_ty)) + if s_ep is not None: + llvmlite.build_store(builder, s_val_elem, s_ep) + return None + + # pop: 返回最后一个元素,count-- + elif string.strcmp(lm_name, "pop") == 0: + p_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + p_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx1) + p_count: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_cpp) + p_nc: llvmlite.Value | t.CPtr = llvmlite.build_sub( + builder, p_count, llvmlite.const_int64(pool, 1)) + llvmlite.build_store(builder, p_nc, p_cpp) + p_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) + p_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx0) + p_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, p_dpp) + p_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) + p_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx4) + p_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_epp) + if p_data is not None and p_esize is not None and p_nc is not None: + p_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, p_nc, p_esize) + p_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, p_data, p_offset) + if p_addr is not None: + p_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( + builder, p_addr, llvmlite.Ptr(pool, lm_elem_ty)) + if p_ep is not None: + return llvmlite.build_load(builder, lm_elem_ty, p_ep) + + # clear: count = 0 + elif string.strcmp(lm_name, "clear") == 0: + c_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) + c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), c_cpp) + return None + + # __iter__: iter_index = 0, return self + elif string.strcmp(lm_name, "__iter__") == 0: + it_idx5: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 5) + it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5) + llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), it_ipp) + return lm_obj + + # append: 直接调用 list.append(self, item) + # append 需要容量检查和内存重分配,逻辑复杂,直接调用 _list.py 中的实现 + elif string.strcmp(lm_name, "append") == 0: + if can >= 1: + ap_sha1: str = self._lookup_module_sha1("_list") + if ap_sha1 is None: + # 依赖模块未编译(_list 未预加入编译链):fail-fast, + # 绝不静默跳过 append(元素永远不会被加入列表) + HandlesType.fatal_error( + cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)", + "InternalCompilerError") + if ap_sha1 is not None: + # 特化类名提取:list.append 的符号名是 + # {sha1}.list[AST|CPtr].append(带类型参数特化名), + # 而非 {sha1}.list.append。lm_obj 类型即特化结构体 + # Ptr(list[AST|CPtr]),从类型解析特化类名拼接调用名, + # 否则 ld.lld undefined symbol(定义端是特化名)。 + ap_spec_nm: str = None + ap_struct_ty: llvmlite.LLVMType | t.CPtr = \ + HandlesStruct.get_struct_type_from_value(lm_obj) + if ap_struct_ty is not None: + ap_spec_nm = HandlesStruct.get_class_name_by_type( + pool, ap_struct_ty) + if ap_spec_nm is None: + ap_spec_nm = "list" + # 触发泛型特化翻译(幂等,MethodsEmitted 防重入): + # list[AST|CPtr].append 的 define 方法体在特化类翻译时 + # 生成。仅构造调用名不触发特化会导致定义缺失 + # (ld.lld undefined symbol: list[AST|CPtr].append)。 + if trans is not None and ap_spec_nm is not None: + lbkt_ap: str = string.strchr(ap_spec_nm, '[') + if lbkt_ap is not None: + rbkt_ap: str = string.strrchr(ap_spec_nm, ']') + if rbkt_ap is not None and rbkt_ap > lbkt_ap: + base_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_ap) - t.CUInt64T(ap_spec_nm)) + arg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_ap) - t.CUInt64T(lbkt_ap) - 1) + if base_len_ap > 0 and arg_len_ap > 0: + base_buf_ap: str = pool.alloc(base_len_ap + 1) + arg_buf_ap: str = pool.alloc(arg_len_ap + 1) + if base_buf_ap is not None and arg_buf_ap is not None: + string.strncpy(base_buf_ap, ap_spec_nm, base_len_ap) + base_buf_ap[base_len_ap] = '\0' + string.strncpy(arg_buf_ap, lbkt_ap + 1, arg_len_ap) + arg_buf_ap[arg_len_ap] = '\0' + args_ap: list[str] | t.CPtr = list[str](pool, 8) + if args_ap is not None: + # 逗号分隔多类型实参(list[X] / dict[K, V]) + cur_ap: str = arg_buf_ap + while cur_ap is not None: + comma_ap: str = string.strchr(cur_ap, ',') + if comma_ap is None: + args_ap.append(cur_ap) + break + seg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(comma_ap) - t.CUInt64T(cur_ap)) + seg_buf_ap: str = pool.alloc(seg_len_ap + 1) + if seg_buf_ap is not None: + string.strncpy(seg_buf_ap, cur_ap, seg_len_ap) + seg_buf_ap[seg_len_ap] = '\0' + args_ap.append(seg_buf_ap) + cur_ap = comma_ap + 1 + HandlesClassDef._specialize_generic_class( + trans, base_buf_ap, args_ap) + # 调用名 "{sha1}.{spec}.append": + # sha1(16) + '.'(1) + spec + '.append'(7) + NUL(1) = spec + 25。 + # 此前 +8 少 1 字节,snprintf 截断末尾 'd' → + # undefined symbol: ...list[AST|CPtr].appen(缺 d)。 + ap_mlen: t.CSizeT = string.strlen(ap_sha1) + \ + string.strlen(ap_spec_nm) + 26 + ap_mangled: str = pool.alloc(ap_mlen) + if ap_mangled is not None: + viperlib.snprintf(ap_mangled, ap_mlen, "%s.%s.append", + ap_sha1, ap_spec_nm) + ap_item_node: ast.AST | t.CPtr = cargs.get(0) + ap_item_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( + builder, pool, mod, ap_item_node, None, 0, trans) + if ap_item_val is not None: + llvmlite.value_set_next(lm_obj, None) + llvmlite.value_set_next(ap_item_val, None) + llvmlite.value_set_next(lm_obj, ap_item_val) + ap_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + self._ensure_method_declare(pool, mod, ap_mangled, ap_ret_ty, lm_obj, 2) + return llvmlite.build_call(builder, ap_mangled, lm_obj, 2, ap_ret_ty, 0) + + return None \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenLib.vp b/App/lib/core/Gen/CallGenLib.vp new file mode 100644 index 0000000..97f09e1 --- /dev/null +++ b/App/lib/core/Gen/CallGenLib.vp @@ -0,0 +1,578 @@ +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 + +# ============================================================ +# CallGenLib - CallGenMixin 拆分(阶段 C):C 库声明 / 返回类型推断 / +# 变长参数 / memcpy / kwargs 调用辅助方法 +# +# 继承 CallGenBase(1 级,TPV self 调用仅支持 1 级父类)。 +# 跨 Mixin 调用统一走 HandlesExprCall 委托(经 _g_gen)。 +# @t.NoVTable:静态绑定。 +# ============================================================ +@t.NoVTable +class CallGenLib(CallGenBase.CallGenBase): + """C 库声明 / 返回类型推断 / kwargs 调用辅助(继承 Base)""" + + def _ensure_c_lib_declare(self, pool: memhub.MemBuddy | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + name: str) -> llvmlite.Function | t.CPtr: + """为已知的 C 库函数创建 declare 声明""" + if pool is None or mod is None or name is None: + return None + + i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) + i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) + + ret_ty: llvmlite.LLVMType | t.CPtr = None + params: int = 0 # 参数数量 + + if string.strcmp(name, "strlen") == 0 or string.strcmp(name, "strlength") == 0: + ret_ty = i64_ty + params = 1 + elif string.strcmp(name, "memset") == 0: + ret_ty = i8_ptr_ty + params = 3 + elif string.strcmp(name, "memcpy") == 0: + ret_ty = i8_ptr_ty + params = 3 + elif string.strcmp(name, "memmove") == 0: + ret_ty = i8_ptr_ty + params = 3 + elif string.strcmp(name, "memcmp") == 0: + ret_ty = i32_ty + params = 3 + elif string.strcmp(name, "strcmp") == 0: + ret_ty = i32_ty + params = 2 + elif string.strcmp(name, "strncmp") == 0: + ret_ty = i32_ty + params = 3 + elif string.strcmp(name, "strcpy") == 0: + ret_ty = i8_ptr_ty + params = 2 + elif string.strcmp(name, "strncpy") == 0: + ret_ty = i8_ptr_ty + params = 3 + elif string.strcmp(name, "strcat") == 0: + ret_ty = i8_ptr_ty + params = 2 + elif string.strcmp(name, "puts") == 0: + ret_ty = i32_ty + params = 1 + elif string.strcmp(name, "atoi") == 0: + ret_ty = i32_ty + params = 1 + elif string.strcmp(name, "atol") == 0: + ret_ty = i64_ty + params = 1 + elif string.strcmp(name, "abs") == 0: + ret_ty = i32_ty + params = 1 + elif string.strcmp(name, "labs") == 0: + ret_ty = i64_ty + params = 1 + else: + return None + + # 创建 declare + fn: llvmlite.Function | t.CPtr = llvmlite.create_declare(pool, mod, name, ret_ty) + if fn is None: + return None + # 添加参数 + if params == 1: + if string.strcmp(name, "abs") == 0: + llvmlite.add_param(pool, fn, i32_ty, "n") + elif string.strcmp(name, "labs") == 0: + llvmlite.add_param(pool, fn, i64_ty, "n") + else: + llvmlite.add_param(pool, fn, i8_ptr_ty, "s") + elif params == 2: + llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") + llvmlite.add_param(pool, fn, i8_ptr_ty, "src") + elif params == 3: + if string.strcmp(name, "memset") == 0: + llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") + llvmlite.add_param(pool, fn, i32_ty, "c") + llvmlite.add_param(pool, fn, i64_ty, "n") + else: + llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") + llvmlite.add_param(pool, fn, i8_ptr_ty, "src") + llvmlite.add_param(pool, fn, i64_ty, "n") + return fn + def _infer_external_func_ret_ty(self, pool: memhub.MemBuddy | t.CPtr, + func_name: str) -> llvmlite.LLVMType | t.CPtr: + """根据函数名推断外部 includes 函数的返回类型 + + 支持三种函数名形式: + 1. 裸名: "parse", "strlen" + 2. 别名: "json_parse"(from X import parse as json_parse) + 3. 带 SHA1 前缀: "240a9a4157959a9f.parse"(跨模块调用 mangled name) + """ + if pool is None or func_name is None: + return llvmlite.Int32(pool) + + # 提取裸函数名:去掉 SHA1 前缀(如 "240a9a4157959a9f.parse" → "parse") + # SHA1 前缀是 16 位十六进制 + '.',检查是否有 '.' 分隔 + bare_name: str = func_name + dot_pos: str = string.strrchr(func_name, 46) # 46 = ord('.') + if dot_pos is not None: + # '.' 后的部分是裸函数名 + bare_name = dot_pos + 1 + + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # 返回 i8* 的函数(指针返回值,截断会导致错误) + if string.strcmp(bare_name, "strchr") == 0 or string.strcmp(func_name, "strchr") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "strrchr") == 0 or string.strcmp(func_name, "strrchr") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "strstr") == 0 or string.strcmp(func_name, "strstr") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "strcpy") == 0 or string.strcmp(func_name, "strcpy") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "strncpy") == 0 or string.strcmp(func_name, "strncpy") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "memset") == 0 or string.strcmp(func_name, "memset") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "memset32") == 0 or string.strcmp(func_name, "memset32") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "memcpy") == 0 or string.strcmp(func_name, "memcpy") == 0: + return i8_ptr_ty + if string.strcmp(bare_name, "memmove") == 0 or string.strcmp(func_name, "memmove") == 0: + return i8_ptr_ty + # JSON 解析函数返回 JsonValue*(指针) + # from json.__parser import parse as json_parse → 别名 json_parse 也需覆盖 + if string.strcmp(bare_name, "parse") == 0 or string.strcmp(func_name, "parse") == 0 or string.strcmp(func_name, "json_parse") == 0: + return i8_ptr_ty + # MemBuddy 方法(当类型信息丢失时可能走外部函数路径) + if string.strcmp(func_name, "alloc") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "calloc") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "realloc") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "alloc_buf") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # VLogger 模块函数(跨模块调用时 stub 未注入,返回指针被截断为 i32 导致崩溃) + if string.strcmp(func_name, "get_logger") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "fmt_buf") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # Config 模块函数(跨模块调用时 stub 未注入,返回 i8* 被 inttoptr i32 截断导致路径损坏) + if string.strcmp(func_name, "get_includes_binary_dir") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + # HandlesType 模块函数(返回 ast.AST|t.CPtr 联合类型,跨模块推断为 i32 导致指针截断) + if string.strcmp(bare_name, "_parse_type_string") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # 返回 i64 的函数 + if string.strcmp(func_name, "strlen") == 0: + return llvmlite.Int64(pool) + if string.strcmp(func_name, "atoll") == 0: + return llvmlite.Int64(pool) + + # 返回 double 的函数 + if string.strcmp(func_name, "atof") == 0: + return llvmlite.Double(pool) + + # 返回 i8 的函数 + if string.strcmp(func_name, "samestr") == 0: + return llvmlite.Int8(pool) + + # Win32 API 返回指针(VOIDPTR/HANDLE)的函数 + # stubs 翻译时未注入,需推断返回 i8* 避免指针被截断为 i32 导致解引用崩溃 + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + if string.strcmp(func_name, "VirtualAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "HeapAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "HeapReAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "HeapCreate") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetProcessHeap") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GlobalAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GlobalFree") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GlobalLock") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "LocalAlloc") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "LocalFree") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetProcAddress") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetModuleHandleA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetModuleHandleW") == 0: + return i8_ptr_ty + # GetCommandLineA/W 返回 LPSTR(i8*):缺则 64 位指针被截成 i32 → + # inttoptr 后 strlen 读到无效地址(SysLibTest argv 段 ASAN 崩溃, + # 非 ASAN 环境随机表现:IDE 0xC0000005 / 部分环境侥幸可读)。 + if string.strcmp(func_name, "GetCommandLineA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "GetCommandLineW") == 0: + return i8_ptr_ty + # gethostbyname 返回 hostent*(i8*) + if string.strcmp(func_name, "gethostbyname") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "LoadLibraryA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "LoadLibraryW") == 0: + return i8_ptr_ty + # Win32 Handle 返回函数(HANDLE = void* = i8*) + if string.strcmp(func_name, "GetStdHandle") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "CreateFileA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "CreateFileW") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "FindFirstFileA") == 0: + return i8_ptr_ty + if string.strcmp(func_name, "FindFirstFileW") == 0: + return i8_ptr_ty + + # Win32 API 返回 i64 (SIZE_T) 的函数 + if string.strcmp(func_name, "VirtualQuery") == 0: + return llvmlite.Int64(pool) + if string.strcmp(func_name, "HeapSize") == 0: + return llvmlite.Int64(pool) + if string.strcmp(func_name, "HeapCompact") == 0: + return llvmlite.Int64(pool) + if string.strcmp(func_name, "GlobalSize") == 0: + return llvmlite.Int64(pool) + + # llvmlite build_* 函数返回类型推断 + # stubs 翻译时未注入,需推断返回类型避免指针被截断为 i32 + # 大多数 build_* 函数返回 Value*(指针),少数终止指令返回 void + if string.strncmp(func_name, "build_", 6) == 0: + # 返回 void 的 build_* 函数(终止指令和无返回值指令) + if string.strcmp(func_name, "build_ret") == 0 or string.strcmp(func_name, "build_ret_void") == 0 or \ + string.strcmp(func_name, "build_store") == 0 or string.strcmp(func_name, "build_br") == 0 or \ + string.strcmp(func_name, "build_cond_br") == 0 or string.strcmp(func_name, "build_unreachable") == 0 or \ + string.strcmp(func_name, "build_switch") == 0: + return llvmlite.Void(pool) + # 其他 build_* 函数返回 Value*(指针) + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # llvmlite 类型工厂函数返回 LLVMType*(指针) + # Int1/Int8/Int16/Int32/Int64/Ptr/Func/Array/Struct/Void/Half/Float/Double/FP128/Label + # new_param_node/new_phi_incoming 返回 ParamNode*/PhiIncoming*(指针) + # const_int32/const_int64/ConstFloat/ConstZero/ConstNull/ConstInt 返回 Value*(指针) + # function_get_name/param_get_ty 等访问器返回指针 + if string.strcmp(func_name, "Int1") == 0 or string.strcmp(func_name, "Int8") == 0 or string.strcmp(func_name, "Int16") == 0 or \ + string.strcmp(func_name, "Int32") == 0 or string.strcmp(func_name, "Int64") == 0 or string.strcmp(func_name, "Ptr") == 0 or \ + string.strcmp(func_name, "Func") == 0 or string.strcmp(func_name, "Array") == 0 or string.strcmp(func_name, "Struct") == 0 or \ + string.strcmp(func_name, "Void") == 0 or string.strcmp(func_name, "Half") == 0 or string.strcmp(func_name, "Float") == 0 or \ + string.strcmp(func_name, "Double") == 0 or string.strcmp(func_name, "FP128") == 0 or string.strcmp(func_name, "Label") == 0 or \ + string.strcmp(func_name, "new_param_node") == 0 or string.strcmp(func_name, "new_phi_incoming") == 0 or \ + string.strcmp(func_name, "const_int32") == 0 or string.strcmp(func_name, "const_int64") == 0 or \ + string.strcmp(func_name, "ConstFloat") == 0 or string.strcmp(func_name, "ConstZero") == 0 or \ + string.strcmp(func_name, "ConstNull") == 0 or string.strcmp(func_name, "ConstInt") == 0 or \ + string.strcmp(func_name, "function_get_name") == 0 or string.strcmp(func_name, "param_get_ty") == 0 or \ + string.strcmp(func_name, "value_get_ty") == 0 or string.strcmp(func_name, "value_get_next") == 0 or \ + string.strcmp(func_name, "function_get_ret_ty") == 0 or string.strcmp(func_name, "function_get_params") == 0 or \ + string.strcmp(func_name, "function_get_param_head") == 0 or string.strcmp(func_name, "param_get_next") == 0: + return llvmlite.Ptr(pool, llvmlite.Int8(pool)) + + # 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324) + # 已知返回指针的函数在上方显式列出(返回 i8*),已知返回 i64 的函数也显式列出 + # 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配 + # x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致 + # WARNING: 未登记的外部函数返回类型默认推断为 i32,若实际返回指针/i64 会被截断 + # --nowarn-register 可抑制此 WARN(自举编译中大量出现,刷屏影响日志收敛) + if VLogger.nowarn_register() == 0: + VLogger.warning( + f"外部函数返回类型未登记,默认推断为 i32(可能截断指针/i64): {func_name}", + "HandlesExprCall") + return llvmlite.Int32(pool) + def _get_external_func_param_ty(self, pool: memhub.MemBuddy | t.CPtr, + func_name: str, + param_idx: int) -> llvmlite.LLVMType | t.CPtr: + """获取外部函数第 param_idx 个参数的期望类型,None 表示用字面量原类型 + + 对 Win32 API 函数的所有非指针参数返回 i64,匹配 declare 中 + ULONG/SIZE_T 被统一翻译为 i64 的情况。 + """ + if pool is None or func_name is None: + return None + + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + + # Win32 API 函数列表:所有非指针参数在 declare 中都是 i64 + # (因为 ULONG/DWORD/SIZE_T 在 LLVM stubs 翻译时都被映射为 i64) + win32_apis: list[str] | t.CPtr = [ + "VirtualAlloc", "VirtualFree", "VirtualProtect", "VirtualQuery", + "VirtualLock", "VirtualUnlock", + "HeapCreate", "HeapDestroy", "HeapAlloc", "HeapReAlloc", + "HeapFree", "HeapSize", "HeapValidate", "HeapCompact", + "GlobalAlloc", "GlobalFree", "GlobalLock", "GlobalUnlock", "GlobalSize", + "LocalAlloc", "LocalFree", + "GetLastError", "SetLastError", + "Sleep", "SleepEx", + "GetTickCount", "GetProcessHeap" + ] + + # list 迭代不支持,用 range + get 替代 + api_count: t.CSizeT = len(win32_apis) + for ai in range(api_count): + api_name: str = win32_apis.get(ai) + if string.strcmp(api_name, func_name) == 0: + return i64_ty + + return None + def _is_sha1_mangled_call(self, call_name: str) -> int: + """判断 call_name 是否为跨模块 Viper 函数("{16位hex}.func" 形式) + + C 库函数(strlen 等裸名)和 Win32 API(VirtualAlloc 等裸名)返回 0, + 不参与精确返回类型解析(走 _infer_external_func_ret_ty 白名单)。 + """ + if call_name is None: + return 0 + first_dot: str = string.strchr(call_name, '.') + if first_dot is None: + return 0 + pre_len: t.CSizeT = t.CSizeT(t.CUInt64T(first_dot) - t.CUInt64T(call_name)) + if pre_len != 16: + return 0 + for hx in range(16): + ch: int = call_name[hx] + if ch < 48 or ch > 57: + if ch < 97 or ch > 102: + if ch < 65 or ch > 70: + return 0 + return 1 + def _emit_llvm_memcpy_intrinsic(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + dst_val: llvmlite.Value | t.CPtr, + src_val: llvmlite.Value | t.CPtr, + num_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: + """将 memcpy 调用映射到 @llvm.memcpy 内联函数 + + 直接接收三个 Value 参数,避免通过 Next 链表遍历(共享 alloca 对象的 + Next 字段可能被其他操作污染,导致链表断裂)。 + """ + if pool is None or builder is None or mod is None: + return None + if dst_val is None or src_val is None or num_val is None: + return None + + # 在函数顶部声明 void_ty,避免后续遮蔽 + void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) + + # 声明 @llvm.memcpy(如未声明) + memcpy_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, "llvm.memcpy") + if memcpy_func is None: + memcpy_func = llvmlite.create_declare(pool, mod, "llvm.memcpy", void_ty) + if memcpy_func is not None: + i8_ptr_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + i64_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + i1_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) + llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "dst") + llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "src") + llvmlite.add_param(pool, memcpy_func, i64_ty_d, "len") + llvmlite.add_param(pool, memcpy_func, i1_ty_d, "isvolatile") + + # 类型转换: dst, src → i8*; num → i64 + # 注意: 使用 value_get_ty 访问器获取 Ty,避免本地 Value 类型字段索引偏移 + i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) + i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) + + # dst → i8* + dst_coerced: llvmlite.Value | t.CPtr = dst_val + dst_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(dst_val) + if HandlesExpr.is_ptr_type(dst_ty) != 0: + dst_coerced = llvmlite.build_bitcast(builder, dst_val, i8_ptr_ty) + else: + dst_bits: int = HandlesExpr.get_llvm_type_bits(dst_ty) + if dst_bits != 0: + if dst_bits < 64: + dst_coerced = llvmlite.build_zext(builder, dst_val, i64_ty) + dst_coerced = llvmlite.build_inttoptr(builder, dst_coerced, i8_ptr_ty) + + # src → i8* + src_coerced: llvmlite.Value | t.CPtr = src_val + src_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(src_val) + if HandlesExpr.is_ptr_type(src_ty) != 0: + src_coerced = llvmlite.build_bitcast(builder, src_val, i8_ptr_ty) + else: + src_bits: int = HandlesExpr.get_llvm_type_bits(src_ty) + if src_bits != 0: + if src_bits < 64: + src_coerced = llvmlite.build_zext(builder, src_val, i64_ty) + src_coerced = llvmlite.build_inttoptr(builder, src_coerced, i8_ptr_ty) + + # num → i64 + num_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, num_val, i64_ty) + + if dst_coerced is None or src_coerced is None or num_coerced is None: + return None + + # 添加 i1 false 参数(isvolatile)— llvm.memcpy 需要 4 个参数 + false_val: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "false") + + # 使用 includes 中的访问器函数构建参数链表,避免本地 Value 类型字段索引偏移 + # (f26cd4c78b4d554c.Value 缺少 GSListNode 的 Next 字段,直接访问 .Next 会修改 .Ty) + llvmlite.value_set_next(dst_coerced, src_coerced) + llvmlite.value_set_next(src_coerced, num_coerced) + if false_val is not None: + llvmlite.value_set_next(num_coerced, false_val) + llvmlite.value_set_next(false_val, None) + else: + llvmlite.value_set_next(num_coerced, None) + + # 使用 build_call 发射 call 指令(内部用 includes Value 类型访问字段,索引正确) + # _ll_name_needs_quote 已对 llvm. 前缀豁免引号 + result: llvmlite.Value | t.CPtr = llvmlite.build_call(builder, "llvm.memcpy", dst_coerced, 4, void_ty, 0) + + # 返回 dst(匹配 C memcpy 语义: 返回 dest 指针) + return dst_coerced + # ============================================================ + # _translate_call_with_kwargs — 带关键字参数的函数调用 + # + # 支持两种语法: + # add(b=4, a=3) — 全关键字乱序 + # greet("Hello", name="World") — 位置 + 关键字混合 + # + # 策略: 遍历 found_func.Params 链表,对每个参数: + # 1. 若位置参数仍有剩余(param_idx < can),取位置参数 + # 2. 否则按参数名匹配关键字参数 + # 3. 按参数顺序构建调用参数链表 + # ============================================================ + + # ============================================================ + # _translate_call_with_kwargs — 带关键字参数的函数调用 + # + # 支持两种语法: + # add(b=4, a=3) — 全关键字乱序 + # greet("Hello", name="World") — 位置 + 关键字混合 + # + # 策略: 遍历 found_func.Params 链表,对每个参数: + # 1. 若位置参数仍有剩余(param_idx < can),取位置参数 + # 2. 否则按参数名匹配关键字参数 + # 3. 按参数顺序构建调用参数链表 + # ============================================================ + def _translate_call_with_kwargs(self, pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + func_name: str, + found_func: llvmlite.Function | t.CPtr, + 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: + """带关键字参数的函数调用,按参数顺序构建调用链表 + + 使用 llvmlite 访问器函数绕过 stub 类型限制: + found_func.Params/RetTy/Name 和 cur_param.Name/Ty/Next 在 stub + 类型中字段不足,直接访问会被 TransPyC 静默跳过。 + """ + head: llvmlite.Value | t.CPtr = None + tail: llvmlite.Value | t.CPtr = None + actual_count: t.CSizeT = 0 + # memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染) + mc_dst1: llvmlite.Value | t.CPtr = None + mc_src1: llvmlite.Value | t.CPtr = None + mc_num1: llvmlite.Value | t.CPtr = None + + # 遍历函数参数链表(使用访问器获取 Head) + param_idx: t.CSizeT = 0 + cur_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) + + while cur_param is not None: + arg_val: llvmlite.Value | t.CPtr = None + if param_idx < can: + # 优先使用位置参数 + arg: ast.AST | t.CPtr = cargs.get(param_idx) + if arg is not None: + arg_val = HandlesExpr.translate_value( + builder, pool, mod, arg, None, 0, trans) + else: + # 查找匹配的关键字参数 + param_name: str = llvmlite.param_get_name(cur_param) + if param_name is not None: + 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 + if HandlesExprCall._kwarg_name_matches(kw.arg, param_name) == 1: + arg_val = HandlesExpr.translate_value( + builder, pool, mod, kw.value, None, 0, trans) + break + + if arg_val is not None: + # 类型转换(按参数类型,使用访问器) + param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param) + if param_ty is not None: + arg_val = HandlesExpr.coerce_to_type(builder, arg_val, param_ty) + arg_val.Next = None + if head is None: + head = arg_val + else: + tail.Next = arg_val + tail = arg_val + # memcpy 专用: 保存前三个参数的独立引用 + if actual_count == 0: + mc_dst1 = arg_val + elif actual_count == 1: + mc_src1 = arg_val + elif actual_count == 2: + mc_num1 = arg_val + actual_count += 1 + + param_idx += 1 + cur_param = llvmlite.param_get_next(cur_param) + + # 使用模块中的实际函数名(可能带 SHA1 前缀,使用访问器) + # declare 和 define 统一用 found_func.Name: + # - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name) + # - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名 + # 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀, + # 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference + call_name: str = func_name + found_name: str = llvmlite.function_get_name(found_func) + if found_name is not None: + call_name = found_name + + # 返回类型(使用访问器) + call_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) + if call_ret_ty is None: + call_ret_ty = self._infer_external_func_ret_ty(pool, func_name) + + # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) + if string.strcmp(func_name, "memcpy") == 0 and actual_count >= 3: + 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) \ No newline at end of file diff --git a/App/lib/core/Gen/CallGenMixin.vp b/App/lib/core/Gen/CallGenMixin.vp index 304f5ac..a3ce443 100644 --- a/App/lib/core/Gen/CallGenMixin.vp +++ b/App/lib/core/Gen/CallGenMixin.vp @@ -70,588 +70,6 @@ ISINSTANCE_CLASS_MAX: t.CDefine = 64 class CallGenMixin(CallGenBase.CallGenBase): """调用分派 Mixin(拆分后顶层,直接继承 CallGenBase——TPV self 调用仅支持 1 级父类)""" - - def _ensure_c_lib_declare(self, pool: memhub.MemBuddy | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - name: str) -> llvmlite.Function | t.CPtr: - """为已知的 C 库函数创建 declare 声明""" - if pool is None or mod is None or name is None: - return None - - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - - ret_ty: llvmlite.LLVMType | t.CPtr = None - params: int = 0 # 参数数量 - - if string.strcmp(name, "strlen") == 0 or string.strcmp(name, "strlength") == 0: - ret_ty = i64_ty - params = 1 - elif string.strcmp(name, "memset") == 0: - ret_ty = i8_ptr_ty - params = 3 - elif string.strcmp(name, "memcpy") == 0: - ret_ty = i8_ptr_ty - params = 3 - elif string.strcmp(name, "memmove") == 0: - ret_ty = i8_ptr_ty - params = 3 - elif string.strcmp(name, "memcmp") == 0: - ret_ty = i32_ty - params = 3 - elif string.strcmp(name, "strcmp") == 0: - ret_ty = i32_ty - params = 2 - elif string.strcmp(name, "strncmp") == 0: - ret_ty = i32_ty - params = 3 - elif string.strcmp(name, "strcpy") == 0: - ret_ty = i8_ptr_ty - params = 2 - elif string.strcmp(name, "strncpy") == 0: - ret_ty = i8_ptr_ty - params = 3 - elif string.strcmp(name, "strcat") == 0: - ret_ty = i8_ptr_ty - params = 2 - elif string.strcmp(name, "puts") == 0: - ret_ty = i32_ty - params = 1 - elif string.strcmp(name, "atoi") == 0: - ret_ty = i32_ty - params = 1 - elif string.strcmp(name, "atol") == 0: - ret_ty = i64_ty - params = 1 - elif string.strcmp(name, "abs") == 0: - ret_ty = i32_ty - params = 1 - elif string.strcmp(name, "labs") == 0: - ret_ty = i64_ty - params = 1 - else: - return None - - # 创建 declare - fn: llvmlite.Function | t.CPtr = llvmlite.create_declare(pool, mod, name, ret_ty) - if fn is None: - return None - # 添加参数 - if params == 1: - if string.strcmp(name, "abs") == 0: - llvmlite.add_param(pool, fn, i32_ty, "n") - elif string.strcmp(name, "labs") == 0: - llvmlite.add_param(pool, fn, i64_ty, "n") - else: - llvmlite.add_param(pool, fn, i8_ptr_ty, "s") - elif params == 2: - llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") - llvmlite.add_param(pool, fn, i8_ptr_ty, "src") - elif params == 3: - if string.strcmp(name, "memset") == 0: - llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") - llvmlite.add_param(pool, fn, i32_ty, "c") - llvmlite.add_param(pool, fn, i64_ty, "n") - else: - llvmlite.add_param(pool, fn, i8_ptr_ty, "dst") - llvmlite.add_param(pool, fn, i8_ptr_ty, "src") - llvmlite.add_param(pool, fn, i64_ty, "n") - return fn - - - def _infer_external_func_ret_ty(self, pool: memhub.MemBuddy | t.CPtr, - func_name: str) -> llvmlite.LLVMType | t.CPtr: - """根据函数名推断外部 includes 函数的返回类型 - - 支持三种函数名形式: - 1. 裸名: "parse", "strlen" - 2. 别名: "json_parse"(from X import parse as json_parse) - 3. 带 SHA1 前缀: "240a9a4157959a9f.parse"(跨模块调用 mangled name) - """ - if pool is None or func_name is None: - return llvmlite.Int32(pool) - - # 提取裸函数名:去掉 SHA1 前缀(如 "240a9a4157959a9f.parse" → "parse") - # SHA1 前缀是 16 位十六进制 + '.',检查是否有 '.' 分隔 - bare_name: str = func_name - dot_pos: str = string.strrchr(func_name, 46) # 46 = ord('.') - if dot_pos is not None: - # '.' 后的部分是裸函数名 - bare_name = dot_pos + 1 - - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - - # 返回 i8* 的函数(指针返回值,截断会导致错误) - if string.strcmp(bare_name, "strchr") == 0 or string.strcmp(func_name, "strchr") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "strrchr") == 0 or string.strcmp(func_name, "strrchr") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "strstr") == 0 or string.strcmp(func_name, "strstr") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "strcpy") == 0 or string.strcmp(func_name, "strcpy") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "strncpy") == 0 or string.strcmp(func_name, "strncpy") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "memset") == 0 or string.strcmp(func_name, "memset") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "memset32") == 0 or string.strcmp(func_name, "memset32") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "memcpy") == 0 or string.strcmp(func_name, "memcpy") == 0: - return i8_ptr_ty - if string.strcmp(bare_name, "memmove") == 0 or string.strcmp(func_name, "memmove") == 0: - return i8_ptr_ty - # JSON 解析函数返回 JsonValue*(指针) - # from json.__parser import parse as json_parse → 别名 json_parse 也需覆盖 - if string.strcmp(bare_name, "parse") == 0 or string.strcmp(func_name, "parse") == 0 or string.strcmp(func_name, "json_parse") == 0: - return i8_ptr_ty - # MemBuddy 方法(当类型信息丢失时可能走外部函数路径) - if string.strcmp(func_name, "alloc") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "calloc") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "realloc") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "alloc_buf") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # VLogger 模块函数(跨模块调用时 stub 未注入,返回指针被截断为 i32 导致崩溃) - if string.strcmp(func_name, "get_logger") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "fmt_buf") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # Config 模块函数(跨模块调用时 stub 未注入,返回 i8* 被 inttoptr i32 截断导致路径损坏) - if string.strcmp(func_name, "get_includes_binary_dir") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - # HandlesType 模块函数(返回 ast.AST|t.CPtr 联合类型,跨模块推断为 i32 导致指针截断) - if string.strcmp(bare_name, "_parse_type_string") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - - # 返回 i64 的函数 - if string.strcmp(func_name, "strlen") == 0: - return llvmlite.Int64(pool) - if string.strcmp(func_name, "atoll") == 0: - return llvmlite.Int64(pool) - - # 返回 double 的函数 - if string.strcmp(func_name, "atof") == 0: - return llvmlite.Double(pool) - - # 返回 i8 的函数 - if string.strcmp(func_name, "samestr") == 0: - return llvmlite.Int8(pool) - - # Win32 API 返回指针(VOIDPTR/HANDLE)的函数 - # stubs 翻译时未注入,需推断返回 i8* 避免指针被截断为 i32 导致解引用崩溃 - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - if string.strcmp(func_name, "VirtualAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "HeapAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "HeapReAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "HeapCreate") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetProcessHeap") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GlobalAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GlobalFree") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GlobalLock") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "LocalAlloc") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "LocalFree") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetProcAddress") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetModuleHandleA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetModuleHandleW") == 0: - return i8_ptr_ty - # GetCommandLineA/W 返回 LPSTR(i8*):缺则 64 位指针被截成 i32 → - # inttoptr 后 strlen 读到无效地址(SysLibTest argv 段 ASAN 崩溃, - # 非 ASAN 环境随机表现:IDE 0xC0000005 / 部分环境侥幸可读)。 - if string.strcmp(func_name, "GetCommandLineA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "GetCommandLineW") == 0: - return i8_ptr_ty - # gethostbyname 返回 hostent*(i8*) - if string.strcmp(func_name, "gethostbyname") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "LoadLibraryA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "LoadLibraryW") == 0: - return i8_ptr_ty - # Win32 Handle 返回函数(HANDLE = void* = i8*) - if string.strcmp(func_name, "GetStdHandle") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "CreateFileA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "CreateFileW") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "FindFirstFileA") == 0: - return i8_ptr_ty - if string.strcmp(func_name, "FindFirstFileW") == 0: - return i8_ptr_ty - - # Win32 API 返回 i64 (SIZE_T) 的函数 - if string.strcmp(func_name, "VirtualQuery") == 0: - return llvmlite.Int64(pool) - if string.strcmp(func_name, "HeapSize") == 0: - return llvmlite.Int64(pool) - if string.strcmp(func_name, "HeapCompact") == 0: - return llvmlite.Int64(pool) - if string.strcmp(func_name, "GlobalSize") == 0: - return llvmlite.Int64(pool) - - # llvmlite build_* 函数返回类型推断 - # stubs 翻译时未注入,需推断返回类型避免指针被截断为 i32 - # 大多数 build_* 函数返回 Value*(指针),少数终止指令返回 void - if string.strncmp(func_name, "build_", 6) == 0: - # 返回 void 的 build_* 函数(终止指令和无返回值指令) - if string.strcmp(func_name, "build_ret") == 0 or string.strcmp(func_name, "build_ret_void") == 0 or \ - string.strcmp(func_name, "build_store") == 0 or string.strcmp(func_name, "build_br") == 0 or \ - string.strcmp(func_name, "build_cond_br") == 0 or string.strcmp(func_name, "build_unreachable") == 0 or \ - string.strcmp(func_name, "build_switch") == 0: - return llvmlite.Void(pool) - # 其他 build_* 函数返回 Value*(指针) - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - - # llvmlite 类型工厂函数返回 LLVMType*(指针) - # Int1/Int8/Int16/Int32/Int64/Ptr/Func/Array/Struct/Void/Half/Float/Double/FP128/Label - # new_param_node/new_phi_incoming 返回 ParamNode*/PhiIncoming*(指针) - # const_int32/const_int64/ConstFloat/ConstZero/ConstNull/ConstInt 返回 Value*(指针) - # function_get_name/param_get_ty 等访问器返回指针 - if string.strcmp(func_name, "Int1") == 0 or string.strcmp(func_name, "Int8") == 0 or string.strcmp(func_name, "Int16") == 0 or \ - string.strcmp(func_name, "Int32") == 0 or string.strcmp(func_name, "Int64") == 0 or string.strcmp(func_name, "Ptr") == 0 or \ - string.strcmp(func_name, "Func") == 0 or string.strcmp(func_name, "Array") == 0 or string.strcmp(func_name, "Struct") == 0 or \ - string.strcmp(func_name, "Void") == 0 or string.strcmp(func_name, "Half") == 0 or string.strcmp(func_name, "Float") == 0 or \ - string.strcmp(func_name, "Double") == 0 or string.strcmp(func_name, "FP128") == 0 or string.strcmp(func_name, "Label") == 0 or \ - string.strcmp(func_name, "new_param_node") == 0 or string.strcmp(func_name, "new_phi_incoming") == 0 or \ - string.strcmp(func_name, "const_int32") == 0 or string.strcmp(func_name, "const_int64") == 0 or \ - string.strcmp(func_name, "ConstFloat") == 0 or string.strcmp(func_name, "ConstZero") == 0 or \ - string.strcmp(func_name, "ConstNull") == 0 or string.strcmp(func_name, "ConstInt") == 0 or \ - string.strcmp(func_name, "function_get_name") == 0 or string.strcmp(func_name, "param_get_ty") == 0 or \ - string.strcmp(func_name, "value_get_ty") == 0 or string.strcmp(func_name, "value_get_next") == 0 or \ - string.strcmp(func_name, "function_get_ret_ty") == 0 or string.strcmp(func_name, "function_get_params") == 0 or \ - string.strcmp(func_name, "function_get_param_head") == 0 or string.strcmp(func_name, "param_get_next") == 0: - return llvmlite.Ptr(pool, llvmlite.Int8(pool)) - - # 默认 i32(整数):与本模块函数定义的默认返回类型一致(HandlesFunctions.py line 324) - # 已知返回指针的函数在上方显式列出(返回 i8*),已知返回 i64 的函数也显式列出 - # 避免使用 i64 导致 stub 声明(declare i64)与实际定义(define i32)类型不匹配 - # x86-64 ABI 中 i32 返回值在 rax 低 32 位,与 define i32 完全一致 - # WARNING: 未登记的外部函数返回类型默认推断为 i32,若实际返回指针/i64 会被截断 - # --nowarn-register 可抑制此 WARN(自举编译中大量出现,刷屏影响日志收敛) - if VLogger.nowarn_register() == 0: - VLogger.warning( - f"外部函数返回类型未登记,默认推断为 i32(可能截断指针/i64): {func_name}", - "HandlesExprCall") - return llvmlite.Int32(pool) - - - def _get_external_func_param_ty(self, pool: memhub.MemBuddy | t.CPtr, - func_name: str, - param_idx: int) -> llvmlite.LLVMType | t.CPtr: - """获取外部函数第 param_idx 个参数的期望类型,None 表示用字面量原类型 - - 对 Win32 API 函数的所有非指针参数返回 i64,匹配 declare 中 - ULONG/SIZE_T 被统一翻译为 i64 的情况。 - """ - if pool is None or func_name is None: - return None - - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - - # Win32 API 函数列表:所有非指针参数在 declare 中都是 i64 - # (因为 ULONG/DWORD/SIZE_T 在 LLVM stubs 翻译时都被映射为 i64) - win32_apis: list[str] | t.CPtr = [ - "VirtualAlloc", "VirtualFree", "VirtualProtect", "VirtualQuery", - "VirtualLock", "VirtualUnlock", - "HeapCreate", "HeapDestroy", "HeapAlloc", "HeapReAlloc", - "HeapFree", "HeapSize", "HeapValidate", "HeapCompact", - "GlobalAlloc", "GlobalFree", "GlobalLock", "GlobalUnlock", "GlobalSize", - "LocalAlloc", "LocalFree", - "GetLastError", "SetLastError", - "Sleep", "SleepEx", - "GetTickCount", "GetProcessHeap" - ] - - # list 迭代不支持,用 range + get 替代 - api_count: t.CSizeT = len(win32_apis) - for ai in range(api_count): - api_name: str = win32_apis.get(ai) - if string.strcmp(api_name, func_name) == 0: - return i64_ty - - return None - - - def _is_sha1_mangled_call(self, call_name: str) -> int: - """判断 call_name 是否为跨模块 Viper 函数("{16位hex}.func" 形式) - - C 库函数(strlen 等裸名)和 Win32 API(VirtualAlloc 等裸名)返回 0, - 不参与精确返回类型解析(走 _infer_external_func_ret_ty 白名单)。 - """ - if call_name is None: - return 0 - first_dot: str = string.strchr(call_name, '.') - if first_dot is None: - return 0 - pre_len: t.CSizeT = t.CSizeT(t.CUInt64T(first_dot) - t.CUInt64T(call_name)) - if pre_len != 16: - return 0 - for hx in range(16): - ch: int = call_name[hx] - if ch < 48 or ch > 57: - if ch < 97 or ch > 102: - if ch < 65 or ch > 70: - return 0 - return 1 - - - def _emit_llvm_memcpy_intrinsic(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - dst_val: llvmlite.Value | t.CPtr, - src_val: llvmlite.Value | t.CPtr, - num_val: llvmlite.Value | t.CPtr) -> llvmlite.Value | t.CPtr: - """将 memcpy 调用映射到 @llvm.memcpy 内联函数 - - 直接接收三个 Value 参数,避免通过 Next 链表遍历(共享 alloca 对象的 - Next 字段可能被其他操作污染,导致链表断裂)。 - """ - if pool is None or builder is None or mod is None: - return None - if dst_val is None or src_val is None or num_val is None: - return None - - # 在函数顶部声明 void_ty,避免后续遮蔽 - void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool) - - # 声明 @llvm.memcpy(如未声明) - memcpy_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, "llvm.memcpy") - if memcpy_func is None: - memcpy_func = llvmlite.create_declare(pool, mod, "llvm.memcpy", void_ty) - if memcpy_func is not None: - i8_ptr_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - i64_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i1_ty_d: llvmlite.LLVMType | t.CPtr = llvmlite.Int1(pool) - llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "dst") - llvmlite.add_param(pool, memcpy_func, i8_ptr_ty_d, "src") - llvmlite.add_param(pool, memcpy_func, i64_ty_d, "len") - llvmlite.add_param(pool, memcpy_func, i1_ty_d, "isvolatile") - - # 类型转换: dst, src → i8*; num → i64 - # 注意: 使用 value_get_ty 访问器获取 Ty,避免本地 Value 类型字段索引偏移 - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - - # dst → i8* - dst_coerced: llvmlite.Value | t.CPtr = dst_val - dst_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(dst_val) - if HandlesExpr.is_ptr_type(dst_ty) != 0: - dst_coerced = llvmlite.build_bitcast(builder, dst_val, i8_ptr_ty) - else: - dst_bits: int = HandlesExpr.get_llvm_type_bits(dst_ty) - if dst_bits != 0: - if dst_bits < 64: - dst_coerced = llvmlite.build_zext(builder, dst_val, i64_ty) - dst_coerced = llvmlite.build_inttoptr(builder, dst_coerced, i8_ptr_ty) - - # src → i8* - src_coerced: llvmlite.Value | t.CPtr = src_val - src_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(src_val) - if HandlesExpr.is_ptr_type(src_ty) != 0: - src_coerced = llvmlite.build_bitcast(builder, src_val, i8_ptr_ty) - else: - src_bits: int = HandlesExpr.get_llvm_type_bits(src_ty) - if src_bits != 0: - if src_bits < 64: - src_coerced = llvmlite.build_zext(builder, src_val, i64_ty) - src_coerced = llvmlite.build_inttoptr(builder, src_coerced, i8_ptr_ty) - - # num → i64 - num_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, num_val, i64_ty) - - if dst_coerced is None or src_coerced is None or num_coerced is None: - return None - - # 添加 i1 false 参数(isvolatile)— llvm.memcpy 需要 4 个参数 - false_val: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "false") - - # 使用 includes 中的访问器函数构建参数链表,避免本地 Value 类型字段索引偏移 - # (f26cd4c78b4d554c.Value 缺少 GSListNode 的 Next 字段,直接访问 .Next 会修改 .Ty) - llvmlite.value_set_next(dst_coerced, src_coerced) - llvmlite.value_set_next(src_coerced, num_coerced) - if false_val is not None: - llvmlite.value_set_next(num_coerced, false_val) - llvmlite.value_set_next(false_val, None) - else: - llvmlite.value_set_next(num_coerced, None) - - # 使用 build_call 发射 call 指令(内部用 includes Value 类型访问字段,索引正确) - # _ll_name_needs_quote 已对 llvm. 前缀豁免引号 - result: llvmlite.Value | t.CPtr = llvmlite.build_call(builder, "llvm.memcpy", dst_coerced, 4, void_ty, 0) - - # 返回 dst(匹配 C memcpy 语义: 返回 dest 指针) - return dst_coerced - - - - - - - - - - - - - - - - - - - - - - - - - - - - # ============================================================ - # _translate_call_with_kwargs — 带关键字参数的函数调用 - # - # 支持两种语法: - # add(b=4, a=3) — 全关键字乱序 - # greet("Hello", name="World") — 位置 + 关键字混合 - # - # 策略: 遍历 found_func.Params 链表,对每个参数: - # 1. 若位置参数仍有剩余(param_idx < can),取位置参数 - # 2. 否则按参数名匹配关键字参数 - # 3. 按参数顺序构建调用参数链表 - # ============================================================ - - # ============================================================ - # _translate_call_with_kwargs — 带关键字参数的函数调用 - # - # 支持两种语法: - # add(b=4, a=3) — 全关键字乱序 - # greet("Hello", name="World") — 位置 + 关键字混合 - # - # 策略: 遍历 found_func.Params 链表,对每个参数: - # 1. 若位置参数仍有剩余(param_idx < can),取位置参数 - # 2. 否则按参数名匹配关键字参数 - # 3. 按参数顺序构建调用参数链表 - # ============================================================ - def _translate_call_with_kwargs(self, pool: memhub.MemBuddy | t.CPtr, - builder: llvmlite.IRBuilder | t.CPtr, - mod: llvmlite.LLVMModule | t.CPtr, - func_name: str, - found_func: llvmlite.Function | t.CPtr, - 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: - """带关键字参数的函数调用,按参数顺序构建调用链表 - - 使用 llvmlite 访问器函数绕过 stub 类型限制: - found_func.Params/RetTy/Name 和 cur_param.Name/Ty/Next 在 stub - 类型中字段不足,直接访问会被 TransPyC 静默跳过。 - """ - head: llvmlite.Value | t.CPtr = None - tail: llvmlite.Value | t.CPtr = None - actual_count: t.CSizeT = 0 - # memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染) - mc_dst1: llvmlite.Value | t.CPtr = None - mc_src1: llvmlite.Value | t.CPtr = None - mc_num1: llvmlite.Value | t.CPtr = None - - # 遍历函数参数链表(使用访问器获取 Head) - param_idx: t.CSizeT = 0 - cur_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func) - - while cur_param is not None: - arg_val: llvmlite.Value | t.CPtr = None - if param_idx < can: - # 优先使用位置参数 - arg: ast.AST | t.CPtr = cargs.get(param_idx) - if arg is not None: - arg_val = HandlesExpr.translate_value( - builder, pool, mod, arg, None, 0, trans) - else: - # 查找匹配的关键字参数 - param_name: str = llvmlite.param_get_name(cur_param) - if param_name is not None: - 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 - if HandlesExprCall._kwarg_name_matches(kw.arg, param_name) == 1: - arg_val = HandlesExpr.translate_value( - builder, pool, mod, kw.value, None, 0, trans) - break - - if arg_val is not None: - # 类型转换(按参数类型,使用访问器) - param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param) - if param_ty is not None: - arg_val = HandlesExpr.coerce_to_type(builder, arg_val, param_ty) - arg_val.Next = None - if head is None: - head = arg_val - else: - tail.Next = arg_val - tail = arg_val - # memcpy 专用: 保存前三个参数的独立引用 - if actual_count == 0: - mc_dst1 = arg_val - elif actual_count == 1: - mc_src1 = arg_val - elif actual_count == 2: - mc_num1 = arg_val - actual_count += 1 - - param_idx += 1 - cur_param = llvmlite.param_get_next(cur_param) - - # 使用模块中的实际函数名(可能带 SHA1 前缀,使用访问器) - # declare 和 define 统一用 found_func.Name: - # - 普通函数的 declare/define 都带 SHA1 前缀(forward_declare_functions 和 stub 注入都用 mangled_name) - # - t.CExtern/t.State/t.CExport 函数的 declare/define 都用裸名 - # 旧逻辑(IsDeclared==1 时用 func_name 裸名)是错误的:stub 注入的 declare Name 已带 SHA1 前缀, - # 用裸名会导致 call @_PathToModuleName 而 define 是 @"sha1._PathToModuleName",链接报 undefined reference - call_name: str = func_name - found_name: str = llvmlite.function_get_name(found_func) - if found_name is not None: - call_name = found_name - - # 返回类型(使用访问器) - call_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func) - if call_ret_ty is None: - call_ret_ty = self._infer_external_func_ret_ty(pool, func_name) - - # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) - if string.strcmp(func_name, "memcpy") == 0 and actual_count >= 3: - 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) - - - - - - - # ============================================================ - # 翻译函数调用 Call(func, args) — 模块级版本 - # ============================================================ - # ============================================================ # 翻译函数调用 Call(func, args) — 模块级版本 # ============================================================ @@ -668,39 +86,18 @@ class CallGenMixin(CallGenBase.CallGenBase): return None func_name: str = HandlesExpr.get_func_name(cl.func) - # super() 语义(2026-08-10):super().method(args) → 静态调用父类方法 - # 形态: Call(func=Attribute(value=Call(func=Name('super')), attr=method)) - # 必须在 Attribute 分派前拦截——否则 value 的 Call(super) 被 translate_value - # 当作普通函数调用报错,且走普通属性调用会命中自身/虚分派而非父类实现。 - if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - sup_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if sup_at.value is not None and sup_at.value.kind() == ast.ASTKind.Call: - sup_cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(sup_at.value) - 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 HandlesExprCall._translate_super_call( - pool, builder, mod, cl, func_name, trans) - # ctraits 宏库编译期谓词:ctraits.isptr(x) 不生成运行时调用, - # 直接按变量存储类型返回编译期常量(CIf 求值失败回退或非 CIf 上下文时兜底, - # 避免生成跨模块调用 ctraits.isptr 触发"模块未注册 SHA1"误导性报错) - if func_name is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - ct_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if ct_at.value is not None and ct_at.value.kind() == ast.ASTKind.Name: - ct_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_at.value) - if ct_nm.id is not None and string.strcmp(ct_nm.id, "ctraits") == 0 \ - and string.strcmp(func_name, "isptr") == 0: - ct_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if ct_args is not None and len(ct_args) >= 1: - ct_arg0: ast.AST | t.CPtr = ct_args.get(0) - if ct_arg0 is not None and ct_arg0.kind() == ast.ASTKind.Name: - ct_nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ct_arg0) - if ct_nm0.id is not None and trans is not None: - ct_r: int = HandlesType.eval_ctraits_isptr(trans.SymTab, ct_nm0.id) - if ct_r > 0: - return llvmlite.const_int32(pool, 1) - return llvmlite.const_int32(pool, 0) + cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args + can: t.CSizeT = 0 + if cargs is not None: + can = len(cargs) + + _tc_h1_super_ctraits_res: llvmlite.Value | t.CPtr = HandlesExprCall._tc_h1_super_ctraits( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + if _tc_h1_super_ctraits_res is not None: + return _tc_h1_super_ctraits_res + + # ---- func_name is None:泛型实例化 + 类型转换 ---- if func_name is None: # 检查是否是 list[int](pool) 形式的泛型实例化调用 # Subscript 节点作为 Call func: 泛型类构造函数 @@ -754,1295 +151,30 @@ class CallGenMixin(CallGenBase.CallGenBase): return HandlesExprCall._translate_t_type_cast(pool, builder, binop_arg_val, binop_ty) return None - # 检测 c.Deref / c.DerefAs / c.Addr 等特殊调用(内联 IR,不生成 call) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - at_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if at_node.value is not None and at_node.value.kind() == ast.ASTKind.Name: - mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_node.value) - if mod_nm.id is not None and string.strcmp(mod_nm.id, "c") == 0: - if string.strcmp(func_name, "Deref") == 0: - return HandlesExprCall.translate_c_deref(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "DerefAs") == 0: - return HandlesExprCall.translate_c_derefas(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "Addr") == 0: - return HandlesExprCall.translate_c_addr(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "Set") == 0: - # c.Set(a, b) = a = b(赋值语义,非指针解引用)。 - # 若当普通函数调用会生成 @Set 引用导致链接失败(undefined reference to `Set')。 - return HandlesExprCall.translate_c_set(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "Load") == 0: - return HandlesExprCall.translate_c_load(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "Asm") == 0: - return HandlesExprCall.translate_c_asm(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "LLVMIR") == 0: - return HandlesExprCall.translate_c_llvmir(pool, builder, mod, cl, trans) - elif string.strcmp(func_name, "LInp") == 0 or string.strcmp(func_name, "LOut") == 0: - # c.LInp/c.LOut 独立调用时返回 0(仅在 c.LLVMIR 的 f-string 内有意义) - return llvmlite.ConstInt(pool, llvmlite.Int32(pool), 0, "0") - elif string.strcmp(func_name, "CIf") == 0: - # 运行时 c.CIf(expr)(编译期求值失败回退):expr 与 0 比较得到 i1 - # 对齐 TPC HandlesExprCall.py L2434-2444 - cif_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args - if cif_args is not None and len(cif_args) >= 1: - cif_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cif_args.get(0), funcs_ptr, func_count, trans) - if cif_arg_val is not None: - cif_bits: int = HandlesExpr.get_llvm_type_bits(cif_arg_val.Ty) - if cif_bits == 1: - return cif_arg_val - if HandlesExpr.is_ptr_type(cif_arg_val.Ty) != 0: - cif_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull( - pool, cif_arg_val.Ty, "null") - return llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cif_arg_val, cif_null) - cif_zero: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0) - return llvmlite.build_icmp( - builder, llvmlite.ICMP_NE, cif_arg_val, cif_zero) - return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 0, "0") - elif string.strcmp(func_name, "CIfdef") == 0 or string.strcmp(func_name, "CIfndef") == 0: - # 运行时 c.CIfdef/c.CIfndef(编译期求值失败回退):恒真 - # 对齐 TPC HandlesExprCall.py L2445-2446 - return llvmlite.ConstInt(pool, llvmlite.Int1(pool), 1, "1") + _tc_h2_c_special_res: llvmlite.Value | t.CPtr = HandlesExprCall._tc_h2_c_special( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + if _tc_h2_c_special_res is not None: + return _tc_h2_c_special_res - cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args - can: t.CSizeT = 0 - if cargs is not None: - can = len(cargs) + _tc_h3_stdarg_cast_res: llvmlite.Value | t.CPtr = HandlesExprCall._tc_h3_stdarg_cast( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + if _tc_h3_stdarg_cast_res is not None: + return _tc_h3_stdarg_cast_res - # ============================================================ - # stdarg 糖函数处理: va_arg / arg / va_start / va_end - # 这些函数在 stdarg.vp 中声明为 pass 体,由编译器在翻译期处理: - # va_arg(ap, type) → %N = va_arg , (LLVM 指令) - # va_arg(ap) → 同上,类型从赋值上下文推断(默认 i32) - # arg(type) → 同上,使用当前函数的隐式 va_list (trans._va_list_ptr) - # va_start(ap, _) → call void @llvm.va_start(i8* %ap) (LLVM intrinsic) - # va_end(ap) → call void @llvm.va_end(i8* %ap) (LLVM intrinsic) - # ============================================================ - if func_name is not None and trans is not None: - if string.strcmp(func_name, "va_arg") == 0: - return HandlesExprCall._translate_va_arg_sugar(pool, builder, mod, cl, cargs, can, - funcs_ptr, func_count, trans) - elif string.strcmp(func_name, "arg") == 0: - return HandlesExprCall._translate_arg_sugar(pool, builder, mod, cl, cargs, can, - funcs_ptr, func_count, trans) - elif string.strcmp(func_name, "va_start") == 0: - return HandlesExprCall._translate_va_start_sugar(pool, builder, mod, cargs, can, - funcs_ptr, func_count, trans) - elif string.strcmp(func_name, "va_end") == 0: - return HandlesExprCall._translate_va_end_sugar(pool, builder, mod, cargs, can, - funcs_ptr, func_count, trans) + _tc_h4_type_casts_res: llvmlite.Value | t.CPtr = HandlesExprCall._tc_h4_type_casts( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + if _tc_h4_type_casts_res is not None: + return _tc_h4_type_casts_res - # 内置强转函数: str(x)/bytes(x) → i8*, int(x) → i32 - # 等价于 (str)(x) / (t.CInt32T)(x) - # 单参数:str(val) → bitcast val to i8* - # int(val) → trunc/sext val to i32 - # 泛型类型参数: 类特化/泛型函数上下文中的 T(x) 先解析 T 为具体类型名 - # (如 "int")再按内建强转处理(Box[int].__init__ 的 self.value = T(v)、 - # combine[T1,T2] 的 T1(b) 依赖此路径) - if func_name is not None and can == 1: - cast_fn_name: str = HandlesType.resolve_generic_type_name(func_name) - if string.strcmp(cast_fn_name, "str") == 0 or string.strcmp(cast_fn_name, "bytes") == 0: - # str(x) / bytes(x) → i8* (bitcast) - cast_arg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - 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 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 - cast_arg_int: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - 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 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 归一化) - # 整数: icmp ne x, 0 → i1 - # 浮点: fcmp one x, 0.0 → i1 - # 指针: icmp ne x, null → i1 - cast_arg_bool: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), funcs_ptr, func_count, trans) - if cast_arg_bool is not None: - arg_bits: int = HandlesExpr.get_llvm_type_bits(cast_arg_bool.Ty) - arg_fbits: int = HandlesExpr.get_llvm_float_bits(cast_arg_bool.Ty) - # 整数: icmp ne x, 0 - if arg_bits != 0: - zero_int: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, arg_bits, 0) - if zero_int is not None: - return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, zero_int) - return None - # 浮点: fcmp one x, 0.0 - if arg_fbits != 0: - zero_ty: llvmlite.LLVMType | t.CPtr = cast_arg_bool.Ty - zero_flt: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, zero_ty, 0.0) - if zero_flt is not None: - return llvmlite.build_fcmp(builder, llvmlite.FCMP_ONE, cast_arg_bool, zero_flt) - return None - # 指针: icmp ne x, null - ptr_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(pool, cast_arg_bool.Ty, "null") - if ptr_null is not None: - return llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cast_arg_bool, ptr_null) - return None - return None + _tc_h5_sizeof_len_isinst_res: llvmlite.Value | t.CPtr = HandlesExprCall._tc_h5_sizeof_len_isinst( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + if _tc_h5_sizeof_len_isinst_res is not None: + return _tc_h5_sizeof_len_isinst_res - # 检测 t.XXX 类型转换: t.CUInt64T(ptr), t.CPtr(val), t.CInt(val) 等 - # 当 func 是 t.XXX 形式且 XXX 是已知类型名时,当作类型转换处理(而非函数调用) - # 支持: - # 单参数: t.CInt(val) → 目标类型 = map_t_type(func_name) - # 双参数: t.CInt(val, t.CPtr) → 目标类型 = Ptr(map_t_type(func_name)) - # t 是内部库,一旦确认为类型转换,绝不跌落到跨模块调用 FATAL 路径 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - tc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if tc_at.value is not None and tc_at.value.kind() == ast.ASTKind.Name: - tc_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_at.value) - if tc_mod_nm.id is not None and string.strcmp(tc_mod_nm.id, "t") == 0: - target_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type(pool, func_name) - if target_ty is not None: - tc_effective_can: t.CSizeT = can - # 双参数形式: t.CInt(val, t.CPtr) → Ptr(target_ty) - # 注意: void* 在 LLVM 中非法,CVoid* 应表示为 i8* - if can == 2: - tc_arg2_node: ast.AST | t.CPtr = cargs.get(1) - tc_arg2_is_cptr: int = 0 - if tc_arg2_node is not None: - # 形式 1: t.CPtr(Attribute 形式) - if tc_arg2_node.kind() == ast.ASTKind.Attribute: - tc_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(tc_arg2_node) - if tc_arg2_at.attr is not None and string.strcmp(tc_arg2_at.attr, "CPtr") == 0: - if tc_arg2_at.value is not None and tc_arg2_at.value.kind() == ast.ASTKind.Name: - tc_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_at.value) - if tc_arg2_nm.id is not None and string.strcmp(tc_arg2_nm.id, "t") == 0: - tc_arg2_is_cptr = 1 - # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用,如 t.CVoid(x, CPtr)) - elif tc_arg2_node.kind() == ast.ASTKind.Name: - tc_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tc_arg2_node) - if tc_arg2_bn.id is not None and string.strcmp(tc_arg2_bn.id, "CPtr") == 0: - tc_arg2_is_cptr = 1 - if tc_arg2_is_cptr != 0: - # CVoid* → i8*(LLVM 中 void* 表示为 i8*) - match target_ty: - case llvmlite.LLVMType.Void(): - target_ty = llvmlite.Int8(pool) - case _: - pass - target_ty = llvmlite.Ptr(pool, target_ty) - tc_effective_can = 1 - if tc_effective_can == 1: - tc_arg_node: ast.AST | t.CPtr = cargs.get(0) - if tc_arg_node is not None: - 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 HandlesExprCall._translate_t_type_cast( - pool, builder, tc_arg_val, target_ty, - func_name, tc_arg_node, trans) - # t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL - return None - - # 模块限定 typedef 转换: posix.mode_t(mode), w32.win32base.HANDLE(v) 等 - # func = Attribute(value=Name(模块), attr=typedef名),此前被误当跨模块函数调用 - # → "跨模块函数 'sha1.mode_t' 返回类型无法精确获取"(SysLibTest os/_posix.vp - # L130 posix.mode_t(mode) 根因)。typedef 名做类型转换(与裸名 BYTEPTR(x) - # 对齐);非 typedef 名继续走模块函数调用。 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - mt_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if mt_at.value is not None and mt_at.value.kind() == ast.ASTKind.Name: - mt_mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(mt_at.value) - if mt_mod_nm.id is not None and string.strcmp(mt_mod_nm.id, "t") != 0 \ - and string.strcmp(mt_mod_nm.id, "c") != 0: - mod_td_ty: llvmlite.LLVMType | t.CPtr = HandlesType.map_t_type( - pool, func_name) - if mod_td_ty is None: - mod_td_str: str = HandlesType.lookup_ctypedef(func_name) - if mod_td_str is not None and HandlesType.is_ctypedef_found() != 0: - mod_td_ast: ast.AST | t.CPtr = HandlesType._parse_type_string( - pool, mod_td_str, 0) - if mod_td_ast is not None: - mod_imp_td: str = None - mod_fi_td: str = None - if trans is not None: - mod_imp_td = trans._imported_modules - mod_fi_td = trans._from_imports - mod_td_ty = HandlesType.resolve_annotation_type( - pool, mod_td_ast, mod_imp_td, mod_fi_td, trans) - if mod_td_ty is not None and can == 1: - 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 HandlesExprCall._translate_t_type_cast( - pool, builder, mt_arg_val, mod_td_ty, - func_name, cargs.get(0), trans) - - # 裸名 typedef 调用: BYTEPTR(ptr1), HANDLE(val), CHARPTR(str) 等 - # 用户通过 `from stdint import *` 导入 typedef 后,可直接用裸名做类型转换 - # map_t_type 包含所有内置 typedef 名称(BYTEPTR/HANDLE/LPCSTR/size_t 等) - # 泛型类型参数转换: 泛型上下文(类特化/泛型函数)中 T(x) → 先解析 T 为具体 - # 类型名(如 "int")再走 map_t_type(Box[int].__init__ 的 self.value = T(v)、 - # combine[T1,T2] 的 T1(b) 依赖此路径) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - bare_fn_name: str = HandlesType.resolve_generic_type_name(func_name) - bare_ty: llvmlite.LLVMType | t.CPtr = None - # 泛型上下文解析出的内建名(如 T→"double"/"float"):map_t_type 只认 t.CDouble, - # 且 float 必须映射 t.CFloat(f32)而非 f64(与注解语义一致) - if string.strcmp(bare_fn_name, "double") == 0: - bare_ty = llvmlite.Double(pool) - elif string.strcmp(bare_fn_name, "float") == 0: - bare_ty = llvmlite.Float(pool) - else: - bare_ty = HandlesType.map_t_type(pool, bare_fn_name) - # 泛型上下文替换出的类型名(如 T→"t.CInt")map_t_type 不识别(只认无前缀名), - # 回退用 resolve_annotation_type 解析(支持 t.CXxx / 结构体类名 / 别名等)。 - # GenericTest4 Box[t.CInt].__init__ 的 self.value = T(v) 依赖此路径。 - if bare_ty is None and string.strcmp(bare_fn_name, func_name) != 0: - gp_ast: ast.AST | t.CPtr = HandlesType._parse_type_string(pool, bare_fn_name, 0) - if gp_ast is not None: - imp_gp: str = None - fi_gp: str = None - if trans is not None: - imp_gp = trans._imported_modules - fi_gp = trans._from_imports - bare_ty = HandlesType.resolve_annotation_type( - pool, gp_ast, imp_gp, fi_gp, trans) - # 泛型类型参数双参数形式: T(val, t.CPtr) → Ptr(T) - # (与 t.CInt(val, t.CPtr) → Ptr(i32) 对齐;vector.vp get() 的 - # typed_ptr = T(offset, t.CPtr) 依赖此路径,否则双参数不进 - # can==1 单参数分支 → 跌落到"裸名调用未定义"误报) - if bare_ty is not None and can == 2: - bare_arg2_node: ast.AST | t.CPtr = cargs.get(1) - bare_arg2_is_cptr: int = 0 - if bare_arg2_node is not None: - # 形式 1: t.CPtr(Attribute 形式) - if bare_arg2_node.kind() == ast.ASTKind.Attribute: - bare_arg2_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(bare_arg2_node) - if bare_arg2_at.attr is not None and string.strcmp(bare_arg2_at.attr, "CPtr") == 0: - if bare_arg2_at.value is not None and bare_arg2_at.value.kind() == ast.ASTKind.Name: - bare_arg2_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_at.value) - if bare_arg2_nm.id is not None and string.strcmp(bare_arg2_nm.id, "t") == 0: - bare_arg2_is_cptr = 1 - # 形式 2: 裸名 CPtr(from t import CPtr 后直接使用) - elif bare_arg2_node.kind() == ast.ASTKind.Name: - bare_arg2_bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(bare_arg2_node) - if bare_arg2_bn.id is not None and string.strcmp(bare_arg2_bn.id, "CPtr") == 0: - bare_arg2_is_cptr = 1 - if bare_arg2_is_cptr != 0: - # CVoid* → i8*(LLVM 中 void* 表示为 i8*) - match bare_ty: - case llvmlite.LLVMType.Void(): - bare_ty = llvmlite.Int8(pool) - case _: - pass - bare_ty = llvmlite.Ptr(pool, bare_ty) - bare_arg_node: ast.AST | t.CPtr = cargs.get(0) - if bare_arg_node is not None: - 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 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: - bare_arg_node: ast.AST | t.CPtr = cargs.get(0) - if bare_arg_node is not None: - 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 HandlesExprCall._translate_t_type_cast( - pool, builder, bare_arg_val, bare_ty, - bare_fn_name, bare_arg_node, trans) - - # 检测 ClassName.__sizeof__() — 返回结构体大小常量(i64) - # __sizeof__ 是内置方法,不走跨模块调用路径 - # 支持: Argument.__sizeof__() 和 w32.win32file.WIN32_FIND_DATAA.__sizeof__() - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - sz_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if sz_at.attr is not None and string.strcmp(sz_at.attr, "__sizeof__") == 0: - if sz_at.value is not None and can == 0: - sz_cls_name: str = None - sz_vk: int = sz_at.value.kind() - if sz_vk == ast.ASTKind.Name: - sz_cls_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sz_at.value) - sz_cls_name = sz_cls_nm2.id - elif sz_vk == ast.ASTKind.Attribute: - sz_inner_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sz_at.value) - sz_cls_name = sz_inner_at.attr - # 最终解析出的结构体类型:类型名命中 → 泛型特化(Stack[T])→ 实例接收者类型(self/obj) - sz_resolved_ty: llvmlite.LLVMType | t.CPtr = None - sz_resolved_name: str = sz_cls_name - if sz_cls_name is not None: - # 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__() - sz_cls_name = HandlesType.resolve_generic_type_name(sz_cls_name) - sz_resolved_name = sz_cls_name - # 去除模块前缀: Viper 解析器将 t.CInt 解析为 Name(id="t.CInt") - # 而非 Attribute(value=Name("t"), attr="CInt"),需要手动提取最后的类名分量 - # "t.CInt" → "CInt", "w32.win32file.WIN32_FIND_DATAA" → "WIN32_FIND_DATAA" - dot_pos: str = string.strrchr(sz_cls_name, '.') - if dot_pos is not None: - sz_cls_name = dot_pos + 1 - # 联合类型(如 AST|t.CPtr)按指针大小处理(8 字节) - # 联合类型在 TPV 中表示指针,可以指向多种类型 - # 对应 TPC 中对 BinOp/BitOr 联合类型的特殊处理 - if string.strstr(sz_cls_name, "|") is not None: - return llvmlite.const_int64(pool, 8) - # 内置类型 sizeof(int=4, str/bytes=8 指针, double=8 等) - sz_builtin: int = -1 - if string.strcmp(sz_cls_name, "int") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "str") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "bytes") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CInt") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "CInt8T") == 0: - sz_builtin = 1 - elif string.strcmp(sz_cls_name, "CInt16T") == 0: - sz_builtin = 2 - elif string.strcmp(sz_cls_name, "CInt32T") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "CInt64T") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CChar") == 0: - sz_builtin = 1 - elif string.strcmp(sz_cls_name, "CDouble") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CFloat") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "CPtr") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CSizeT") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "CBool") == 0: - sz_builtin = 1 - elif string.strcmp(sz_cls_name, "bool") == 0: - sz_builtin = 1 - # 泛型 T 解析出的裸内建名(resolve_generic_type_name 返回 - # _infer_generic_ctor_type_arg 的输出,如 T→"double"/"float"): - # 缺省会让 sz_builtin=-1 → 落到"回退 2"把 Name(T) 当值翻译 → - # NameError(VectorGenericTest Vector[double].__init__ 回归根因) - elif string.strcmp(sz_cls_name, "double") == 0: - sz_builtin = 8 - elif string.strcmp(sz_cls_name, "float") == 0: - sz_builtin = 4 - elif string.strcmp(sz_cls_name, "char") == 0: - sz_builtin = 1 - if sz_builtin >= 0: - # 注意: 必须用 const_int64 而非 ConstInt(...,"0") - # ConstInt 的 name 参数是 IR 文本表示,ValuePrint 输出时使用 Name 而非 IntVal - # 硬编码 "0" 会导致 IR 输出 i64 0 而非实际值 - return llvmlite.const_int64(pool, sz_builtin) - sz_resolved_ty = HandlesStruct.get_struct_type(sz_cls_name) - # 回退 1: 泛型类引用接收者 Stack[T].__sizeof__() — Subscript → 特化后计算大小 - # (GenericTest2 Stack.type_size 依赖此路径) - if sz_resolved_ty is None and trans is not None and sz_vk == ast.ASTKind.Subscript: - sub_sz: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(sz_at.value) - 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 = 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: - gai_sz: t.CSizeT = len(gen_args_sz) - gai2_sz: t.CSizeT = 0 - for gai2_sz in range(gai_sz): - gres_sz: str = HandlesType.resolve_generic_type_name( - gen_args_sz.get(gai2_sz)) - gargs_resolved.append(gres_sz) - spec_sz: str = HandlesClassDef._specialize_generic_class( - trans, gen_nm_sz.id, gargs_resolved) - if spec_sz is not None: - sz_resolved_name = spec_sz - sz_resolved_ty = HandlesStruct.get_struct_type(spec_sz) - # 回退 2: 实例接收者 self.__sizeof__() / obj.__sizeof__() — 用接收者值的实际类型 - # (GenericTest2 Stack.size_of 依赖此路径;self 在方法内是 Ptr(Stack[int])) - # 数组变量接收者 bl_count.__sizeof__()(t.CArray[T, N] 变量)→ alloca - # 指针 Ptr([N x T]),算 N*elem_size(TPC _HandleSizeofLlvm 数组分支; - # zhuff.vp memset(bl_count, 0, bl_count.__sizeof__()) 依赖) - if sz_resolved_ty is None: - inst_sz_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, sz_at.value, None, 0, trans) - if inst_sz_val is not None and inst_sz_val.Ty is not None: - match inst_sz_val.Ty: - case llvmlite.LLVMType.Ptr(inst_inner_sz): - match inst_inner_sz: - case llvmlite.LLVMType.Struct(_, _, _): - sz_resolved_ty = inst_inner_sz - case llvmlite.LLVMType.Array(_, _): - sz_resolved_ty = inst_inner_sz - case _: - pass - case llvmlite.LLVMType.Struct(_, _, _): - sz_resolved_ty = inst_sz_val.Ty - case llvmlite.LLVMType.Array(_, _): - # 全局数组变量(模块级 t.CArray[T,N])translate_value - # 返回数组值 [N x T](非指针);局部数组返回 alloca - # 指针 Ptr([N x T]) 走上方 Ptr(Array) 分支。 - # pyzlib_error_msg.__sizeof__() 依赖(全局字符缓冲)。 - sz_resolved_ty = inst_sz_val.Ty - case _: - pass - if sz_resolved_ty is not None: - sz_val: int = HandlesClassDef._get_type_size(sz_resolved_ty) - if sz_val > 0: - return llvmlite.const_int64(pool, sz_val) - # 类型已注册但大小为 0(opaque struct 或字段链表未填充):Python 风格报错终止 - HandlesType.fatal_error( - sz_at, f"类型 '{sz_resolved_name}' 已注册但大小为 0(字段链表未填充),无法计算大小", - "TypeError") - # 类型未注册:Python 风格报错终止,不静默返回 0(会导致 malloc(0)/alloc(0) 堆溢出) - if sz_resolved_name is None: - sz_resolved_name = "(unknown)" - HandlesType.fatal_error( - sz_at, f"类型 '{sz_resolved_name}' 未在结构体表中注册,无法计算大小", - "TypeError") - - # 检测 len(obj) — 返回 list 对象的 __count__ 字段(偏移 8,i64) - # __len__ 是 list[T] 的内置方法,list 是泛型类不注册 struct - # 注意: 必须用 translate_value 而非 translate_name_value,因为 len_at.value - # 可能是 Attribute 节点(如 md_ags.args),translate_name_value 只处理 Name 节点, - # 对 Attribute 会错误返回 i32 0,导致 GEP base 不是指针(base of getelementptr must be a pointer) - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - len_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if len_at.attr is not None and string.strcmp(len_at.attr, "__len__") == 0: - if len_at.value is not None and can == 0: - obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, len_at.value, funcs_ptr, func_count, trans) - if obj_val is not None and obj_val.Ty is not None: - # 防御性类型检查: obj_val 必须是指针类型才能做 GEP - # 如果 translate_value 返回 i32 (如 CDefine 常量被误解析、 - # 模块属性前向引用回退为 i32),GEP base 会是 i32 而非指针, - # 导致 llc 报错 "base of getelementptr must be a pointer" - if HandlesExpr.is_ptr_type(obj_val.Ty) == 0: - # 类型推断失败(非指针/结构体):fail-fast,绝不返回 0 掩盖错误 - HandlesType.fatal_error( - len_at.value, "len() 参数类型推断失败(非指针/结构体)", "TypeError") - i64_ty_len: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - # 注意: 必须用 const_int64 而非 ConstInt(...,"0") - # ConstInt 的 name 参数 "0" 会被当作 IR 文本值输出 i64 0 - # 导致 GEP 索引为 0(访问 __data__)而非 1(访问 __count__) - idx_one: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - count_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep( - builder, i64_ty_len, obj_val, idx_one) - if count_ptr is not None: - return llvmlite.build_load(builder, i64_ty_len, count_ptr) - - # 检测 len() 内置函数调用 — 结构体对象走 __len__ 方法,字符串走 strlen - # len(s) 对 str 类型调用 strlen,返回 i64 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - if func_name is not None and string.strcmp(func_name, "len") == 0: - if can == 1: - len_arg_node: ast.AST | t.CPtr = cargs.get(0) - if len_arg_node is not None: - len_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, len_arg_node, None, 0, trans) - if len_val is not None: - # len(数组):t.CArray[T, N] → 常量 N(对齐 TPC - # _HandleLenLlvm 的 ArrayType.count 分支)。数组变量 - # translate_value 可能返回 Ptr([N x T])(alloca 指针) - # 或 [N x T] 值,两种都识别;否则会误走 strlen 把 - # 数组首元素当字符串读 → 垃圾长度。 - len_is_arr: int = 0 - len_arr_n: int = 0 - if len_val.Ty is not None: - if HandlesExpr.is_ptr_type(len_val.Ty) != 0: - len_ap: llvmlite.LLVMType | t.CPtr = len_val.Ty.Pointee - if len_ap is not None: - match len_ap: - case llvmlite.LLVMType.Array(_, len_arr_cnt): - len_is_arr = 1 - len_arr_n = len_arr_cnt - case _: - pass - else: - match len_val.Ty: - case llvmlite.LLVMType.Array(_, len_arr_cnt): - len_is_arr = 1 - len_arr_n = len_arr_cnt - case _: - pass - if len_is_arr != 0: - return llvmlite.const_int64(pool, len_arr_n) - # len(对象):有 __len__ 就调用,没有就编译期报错 - # (用户要求 2026-08-15,不再静默 strlen 读对象首字段): - # - list 泛型内置容器:__len__ 由 list 内置分支内联 - # (读 __count__,偏移 1),不生成方法函数 - # (_is_list_builtin_method,通用判断非特判) - # - 普通类:调用 {Class}.__len__ 函数 - # - 都没有:fatal_error - # str(Ptr(Int8))保持 strlen(内建语义)。 - len_struct_ty: llvmlite.LLVMType | t.CPtr = \ - HandlesStruct.get_struct_type_from_value(len_val) - if len_struct_ty is not None: - len_cls_nm: str = HandlesStruct.get_class_name_by_type( - pool, len_struct_ty) - if len_cls_nm is None: - HandlesType.fatal_error( - len_arg_node, "len() 参数类型推断失败(结构体类名未知)", - "TypeError") - # list 内置 __len__:读 __count__(GEP 偏移 1,i64) - 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( - builder, i64_ty_lb, len_val, idx_one_lb) - if cnt_ptr_lb is not None: - return llvmlite.build_load(builder, i64_ty_lb, cnt_ptr_lb) - len_lookup: str = pool.alloc(128) - if len_lookup is not None: - viperlib.snprintf(len_lookup, 128, "%s.__len__", len_cls_nm) - len_fn2: llvmlite.Function | t.CPtr = self.find_func_in_module( - mod, len_lookup) - if len_fn2 is not None: - len_ret_ty2: llvmlite.LLVMType | t.CPtr = \ - llvmlite.function_get_ret_ty(len_fn2) - len_fn_name2: str = \ - llvmlite.function_get_name(len_fn2) - if len_ret_ty2 is not None and len_fn_name2 is not None: - # self 参数类型对齐(按方法首个形参 bitcast) - len_self_arg2: llvmlite.Value | t.CPtr = len_val - len_first_param2: llvmlite.Param | t.CPtr = \ - llvmlite.function_get_param_head(len_fn2) - if len_first_param2 is not None: - len_self_ty2: llvmlite.LLVMType | t.CPtr = \ - llvmlite.param_get_ty(len_first_param2) - if len_self_ty2 is not None and len_val.Ty is not None: - len_self_arg2 = llvmlite.build_bitcast( - builder, len_val, len_self_ty2) - len_self_arg2.Next = None - return llvmlite.build_call( - builder, len_fn_name2, len_self_arg2, - 1, len_ret_ty2, 0) - # len_fn2 未命中(跨模块方法):如 ndarray[t.CDouble].__len__ - # 定义在 numpy——泛型特化方法无 stub declare,find_func_in_module - # 后缀匹配查不到。用结构体所属模块 sha1 构造 - # {sha1}.{cls}.__len__ 精确调用名(对齐 _translate_method_call - # 跨模块调用名构造),返回类型从 text.ll/vpi 精确解析, - # _ensure_method_declare 建 declare 后调用。 - len_cls_sha1_x: str = HandlesStruct.get_struct_sha1(len_cls_nm) - if len_cls_sha1_x is not None: - # 缓冲区需容纳 "{sha1}.{cls}.__len__": - # 2 个点 + "__len__"(7) + NUL = 10;+8 会截断 - # 末两位 → 符号变 ".__len" 链接 undefined - # (NumpyTest test_len 链接错误根因) - len_ml_x: t.CSizeT = string.strlen(len_cls_sha1_x) \ - + string.strlen(len_cls_nm) + 10 - len_mangled_x: str = pool.alloc(len_ml_x) - if len_mangled_x is not None: - viperlib.snprintf(len_mangled_x, len_ml_x, - "%s.%s.__len__", len_cls_sha1_x, len_cls_nm) - len_ret_x: llvmlite.LLVMType | t.CPtr = \ - self._LookupMethodRetTyFromTextLL( - pool, len_cls_sha1_x, len_cls_nm, "__len__") - if len_ret_x is None: - len_ret_x = self._lookup_method_ret_ty_via_vpi( - pool, len_cls_sha1_x, len_cls_nm, "__len__") - if len_ret_x is not None: - # self 参数按对象实际类型 Ptr(len_struct_ty)(与定义侧 - # 同名类型链接匹配);len_val 已是 load 后的对象指针。 - # Value 链直接作 param_head(同跨模块调用模式)。 - len_self_x: llvmlite.Value | t.CPtr = len_val - len_self_x.Next = None - self._ensure_method_declare( - pool, mod, len_mangled_x, len_ret_x, - len_self_x, 1) - return llvmlite.build_call( - builder, len_mangled_x, len_self_x, - 1, len_ret_x, 0) - # fail-fast:类没有 __len__(用户要求编译期报错) - HandlesType.fatal_error( - len_arg_node, - f"len() 参数类型 '{len_cls_nm}' 没有 __len__ 方法", - "TypeError") - # 非结构体:str(Ptr(Int8))走 strlen;其它类型 fail-fast - len_arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(len_val) - len_is_str: int = 0 - if len_arg_ty is not None and HandlesExpr.is_ptr_type(len_arg_ty) != 0: - match len_arg_ty: - case llvmlite.LLVMType.Ptr(len_pt_ty): - if len_pt_ty is not None: - match len_pt_ty: - case llvmlite.LLVMType.Int(len_pt_bits): - if len_pt_bits == 8: - len_is_str = 1 - case _: - pass - case _: - pass - if len_is_str != 0: - # 确保 strlen 在模块中有声明 - strlen_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, "strlen") - if strlen_fn is None: - i64_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ptr_ty_ln: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - strlen_fn = llvmlite.create_declare(pool, mod, "strlen", i64_ty_ln) - if strlen_fn is not None: - llvmlite.add_param(pool, strlen_fn, i8_ptr_ty_ln, "s") - # 参数类型转换为 i8* - i8_ptr_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool)) - len_coerced: llvmlite.Value | t.CPtr = len_val - if HandlesExpr.is_ptr_type(len_arg_ty) != 0: - len_coerced = llvmlite.build_bitcast(builder, len_val, i8_ptr_ty_ln2) - # 构建单参数链表并调用 strlen - len_coerced.Next = None - i64_ty_ln2: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - return llvmlite.build_call(builder, "strlen", len_coerced, 1, i64_ty_ln2, 0) - # fail-fast:非字符串/数组/对象,无法求长度 - HandlesType.fatal_error( - len_arg_node, "len() 参数类型不支持(非字符串/数组/对象)", - "TypeError") - - # 检测 isinstance() 内置函数调用 — 运行时 vtable 子类集合比较 - # isinstance(obj, Cls):obj 头部 vtable 指针 ∈ {Cls 及全部子类 vtable}; - # NoVTable 目标类回退编译时静态判断(详见 _translate_isinstance)。 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - if func_name is not None and string.strcmp(func_name, "isinstance") == 0: - if can >= 2: - is_res: llvmlite.Value | t.CPtr = HandlesExprCall._translate_isinstance( - pool, builder, mod, cargs.get(0), cargs.get(1), trans) - if is_res is not None: - return is_res - - # 检测类名静态/类方法调用: ClassName.method(args) - # 当 cl.func 是 Attribute、value 是已注册结构体类名(非普通变量)时, - # 且方法带 @staticmethod/@classmethod 元数据,走静态调用路径 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - st_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if st_at is not None and st_at.value is not None and trans is not None: - if st_at.value.kind() == ast.ASTKind.Name: - st_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(st_at.value) - if st_nm.id is not None: - # 仅当该名称不是普通变量且是已注册结构体类名时尝试静态/类方法 - # 追加"非导入模块"条件:st_nm.id 是模块名(import X as Y 把别名 - # Y 加入 _imported_modules,HandlesImports L344-347)时,X.Y(...) - # 是模块限定调用(Module.Class 构造 / Module.func 函数),不是 - # ClassName.method(obj,args)。模块名与类名同名时(CompilerFactory. - # CompilerFactory(...) 构造 / .set_factory(...) 函数,main.vp - # 追加84/84b 根因)get_struct_type(st_nm.id) 会误判为类名 → - # 把首实参当 self 传 _call_method_on_ptr → 返回类型查 "X.Y" 永远 - # 落空 → fail-fast。模块限定调用由尾部 ctor 检测(L7441 模块限定 - # 构造)与跨模块函数路径正确路由。 - st_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, st_nm.id) - if st_var is None and HandlesStruct.get_struct_type(st_nm.id) is not None \ - and HandlesImports.is_module_imported( - trans._imported_modules, st_nm.id) == 0: - # REnum 变体构造优先于静态/类方法调用: - # ClassName.VariantName(args)(如 Option.Some(42))若被当 - # "实例方法经类名调用"处理,会把首实参 42 当 self 传 - # _call_method_on_ptr → 查 "Option.Some" 方法返回类型 → - # 跨模块 stub 未命中 → fail-fast(EnumTest "方法 - # 'Option.Some' 返回类型无法确定" 根因)。REnum 变体 - # 构造检测原在 translate_call 尾部(L7493),被本分支 - # 拦截先执行不到,此处提前检测。 - if HandlesClassDef._is_renum_class_name(st_nm.id) != 0: - rc_tag_sc: int = HandlesClassDef._lookup_renum_variant_in_class( - st_nm.id, func_name) - if rc_tag_sc >= 0: - 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 = HandlesExprCall._translate_static_class_call( - pool, builder, mod, st_nm.id, func_name, cl, trans) - if st_res is not None: - return st_res - # 实例方法经类名调用: ClassName.method(obj, args) → obj.method(args) - # (Python 语义,首参是 self 对象;zdeflate.vp - # zdeflate_stream.find_match(s, data, ...) 根因:_translate_ - # static_class_call 对非静态方法返回 None 后,ClassName 被 - # 通用路径当模块名 → "跨模块调用找不到模块 SHA1") - # st_nm.id == func_name(类名==方法名,如 CompilerFactory. - # CompilerFactory(...))不是实例方法调用而是构造调用: - # 模块名与类名同名时本分支把模块限定类构造误判为 - # ClassName.method(obj,args),首实参当 self 传 → - # _call_method_on_ptr 查 "X.X" 返回类型永远落空 → - # fail-fast(main.vp CompilerFactory 追加84 根因)。 - # 跳过本分支,落到 translate_call 尾部的 ctor 检测 - # (L7426 模块限定类构造 find_struct_by_module 正确路由)。 - if can >= 1 and cargs is not None \ - and string.strcmp(st_nm.id, func_name) != 0: - im_self: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, cargs.get(0), None, 0, trans) - if im_self is not None: - im_rem: t.CSizeT | t.CPtr = None - if can >= 2: - im_rem = pool.alloc(t.CSizeT(can - 1) * 8) - if im_rem is not None: - ri_im: t.CSizeT - for ri_im in range(can - 1): - im_rv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - 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 = 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: - return im_res - elif st_at.value.kind() == ast.ASTKind.Attribute: - # 模块限定静态调用: module.ClassName.static_method(args) - # cl.func = Attribute(value=Attribute(value=Name(module), - # attr=ClassName), attr=method_name) - # 此前未检测 → 走通用路径把 method_name 当裸函数解析, - # 生成 call i32 @from_long(无类名/SHA1 前缀)→ 链接 - # undefined reference(CPythonTest PyLongObj.from_long 根因) - st_at2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(st_at.value) - if st_at2 is not None and st_at2.attr is not None and st_at2.value is not None: - 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 = HandlesExprCall._translate_static_class_call( - pool, builder, mod, st_at2.attr, func_name, cl, trans) - if st_res2 is not None: - return st_res2 - - # 检测方法调用: obj.method(args) - # 当 cl.func 是 Attribute 且 obj 是已注册的结构体变量时,翻译为方法调用 - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if method_at is not None and method_at.value is not None: - if method_at.value.kind() == ast.ASTKind.Name and trans is not None: - method_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(method_at.value) - if method_obj_nm.id is not None: - # 查找对象变量 - obj_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, method_obj_nm.id) - if obj_var is not None and obj_var.Ty is not None: - # 检查是否为 Ptr(Struct(...))(结构体值变量) - # 或 Ptr(Ptr(Struct(...)))(指针变量,需 load) - match obj_var.Ty: - case llvmlite.LLVMType.Ptr(obj_struct_ty): - class_nm: str = HandlesStruct.get_class_name_by_type( - pool, obj_struct_ty) - if class_nm is not None: - # list 泛型内置容器方法(append/get/set/pop/clear/__iter__/ - # __len__/__getitem__/__setitem__)由下方 list 内置分支 - # (L5848 起)内联 GEP 处理,不注册方法函数;若走 - # _translate_method_call 会查 append 返回类型(函数/text.ll/ - # vpi stub 均未命中)→ fail-fast。检测到 list 方法时 - # 跳过 method_call,落到内置分支(NewAstTest body.append 根因)。 - 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)) - # load 获取实际指针 Ptr(Struct) 后再查找 - match obj_struct_ty: - case llvmlite.LLVMType.Ptr(inner_struct_ty): - inner_nm: str = HandlesStruct.get_class_name_by_type( - pool, inner_struct_ty) - if inner_nm is not None: - # list 内置方法同样跳过(同 Ptr(Struct) 分支) - 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 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 = HandlesExprCall._translate_fakeduck_call( - pool, builder, mod, None, func_name, cl, trans) - if fd_name_res is not None: - return fd_name_res - # AnnotClassName 回退:联合类型简化为 Ptr(i8) 时, - # 通过原始类型注解的类名查找结构体 - var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry( - trans.SymTab, method_obj_nm.id) - if var_entry is not None and var_entry.AnnotClassName is not None: - annot_val: str = var_entry.AnnotClassName - # 解析模块限定名 "memhub.MemBuddy" → mod_nm="memhub", cls_nm="MemBuddy" - dot_ptr: str = string.strrchr(annot_val, '.') - cls_nm2: str = annot_val - mod_nm2: str = None - if dot_ptr is not None: - cls_nm2 = dot_ptr + 1 - total_len_av: t.CSizeT = string.strlen(annot_val) - cls_len_av: t.CSizeT = string.strlen(cls_nm2) - mod_len2: t.CSizeT = total_len_av - cls_len_av - 1 - mod_nm2 = pool.alloc(mod_len2 + 1) - if mod_nm2 is not None: - string.strncpy(mod_nm2, annot_val, mod_len2) - mod_nm2[mod_len2] = '\0' - # 检查结构体是否已注册 - if HandlesStruct.get_struct_type(cls_nm2) is not None: - # list 内置方法跳过 method_call(同 Ptr(Struct) 分支), - # 落到下方 list 内置分支 - 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 HandlesExprCall._translate_method_call( - pool, builder, mod, cls_nm2, func_name, - obj_ptr2, cl, trans) - else: - # list 内置方法跳过(结构体未注册路径同样不能 - # 构造 {sha1}.{cls}.append 调用名——list 方法无此函数) - 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 = HandlesExprCall._translate_fakeduck_call( - pool, builder, mod, cls_nm2, func_name, cl, trans) - if fd_res is not None: - return fd_res - # 结构体未注册(跨模块依赖未翻译): - # 用模块名查 SHA1 构造方法调用名 - sha1_fc: str = None - if mod_nm2 is not None: - sha1_fc = self._lookup_module_sha1(mod_nm2) - if sha1_fc is not None: - # 构造 "{sha1}.{cls_nm2}.{func_name}" 调用名 - mlen3: t.CSizeT = string.strlen(sha1_fc) + string.strlen(cls_nm2) + string.strlen(func_name) + 3 - mangled3: str = pool.alloc(mlen3) - if mangled3 is not None: - viperlib.snprintf(mangled3, mlen3, "%s.%s.%s", sha1_fc, cls_nm2, func_name) - # load obj_ptr (self) - i8_ptr_ty3: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( - pool, llvmlite.Int8(pool)) - obj_ptr3: llvmlite.Value | t.CPtr = llvmlite.build_load( - builder, i8_ptr_ty3, obj_var) - if obj_ptr3 is not None: - # 构建参数链表: obj_ptr3 (self) → 其他参数 - llvmlite.value_set_next(obj_ptr3, None) - head3: llvmlite.Value | t.CPtr = obj_ptr3 - tail3: llvmlite.Value | t.CPtr = obj_ptr3 - for ai3 in range(can): - arg3: ast.AST | t.CPtr = cargs.get(ai3) - if arg3 is not None: - arg_val3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, arg3, None, 0, trans) - if arg_val3 is not None: - llvmlite.value_set_next(arg_val3, None) - llvmlite.value_set_next(tail3, arg_val3) - tail3 = arg_val3 - total3: int = 1 + can - ret_ty3: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty( - pool, cls_nm2, func_name) - if ret_ty3 is None: - ret_ty3 = self._LookupMethodRetTyFromTextLL( - pool, sha1_fc, cls_nm2, func_name) - if ret_ty3 is None: - # 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单) - ret_ty3 = self._lookup_method_ret_ty_via_vpi( - pool, sha1_fc, cls_nm2, func_name) - if ret_ty3 is None: - # 本分支仅在"注解类结构体未注册"时到达(L6932 else): - # 类未注册 → 无法沿 MRO 解析 Mixin 方法定义模块。 - # 例如 g 注解 Generator.Generator,但 _register_cdefine_from_value - # 定义在 AssignGenMixin.vp——其 text.ll 的 define 名是 - # {AssignGenMixin_sha1}.AssignGenMixin.xxx,查 - # {Generator_sha1}.Generator.xxx 永远落空(追加80d 根因; - # sha1_fc 存在 + text.ll 存在仍查不到,固定 256KB 截断 - # 只是次要因素)。必须标记 pending:等 Generator 注册后 - # 下遍走 L6919 已注册分支 → _translate_method_call 沿 - # MRO 链找到 AssignGenMixin → 精确解析。真正不存在的 - # 类/方法由 Phase A 收敛检查兜底,绝不在此 fail-fast - # 中断多遍收敛(对齐追加77/77b 类 defer 原则)。 - if trans is not None: - trans._deps_pending = 1 - ret_ty3 = llvmlite.Void(pool) - self._ensure_method_declare(pool, mod, mangled3, ret_ty3, head3, total3) - return llvmlite.build_call(builder, mangled3, head3, total3, ret_ty3, 0) - - # ============================================================ - # 检测表达式接收者方法调用: (expr).method(args) - # - # 当 method_at.value 是 BinOp/Subscript/Call 等非 Name/Attribute 表达式时 - # (如 (a + b).dot(c)、(v1 + v2) * 3.0),先 translate_value 求值接收者, - # 再从值的 LLVM 类型(Ptr(Struct))解析类名,走方法调用路径。 - # ============================================================ - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - expr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if expr_method_at is not None and expr_method_at.value is not None and trans is not None: - evk: int = expr_method_at.value.kind() - # Attribute 接收者区分两种形态: - # 1. 模块限定路径(os._win32.exists / w32.fileio.fn)——根名是已导入 - # 模块或 t/c,留给下方跨模块限定路径处理 - # 2. 字段链表达式接收者(self.writer.write_bits / self.pool.alloc) - # ——根名是对象(self/局部变量),必须走本方法调用路径; - # 否则被模块限定路径误判 xmod_path="self.writer" → "找不到模块 - # SHA1"(zdeflate.vp write_fixed_block 根因) - is_mod_path_expr: int = 0 - if evk == ast.ASTKind.Attribute: - expr_root: ast.AST | t.CPtr = expr_method_at.value - while expr_root is not None and expr_root.kind() == ast.ASTKind.Attribute: - expr_root = (ast.Attribute | t.CPtr)(expr_root).value - if expr_root is not None and expr_root.kind() == ast.ASTKind.Name: - expr_root_nm: str = (ast.Name | t.CPtr)(expr_root).id - if expr_root_nm is not None: - if string.strcmp(expr_root_nm, "t") == 0 or \ - string.strcmp(expr_root_nm, "c") == 0: - is_mod_path_expr = 1 - elif trans._imported_modules is not None: - if HandlesImports.is_module_imported( - trans._imported_modules, expr_root_nm) != 0: - is_mod_path_expr = 1 - if evk != ast.ASTKind.Name and is_mod_path_expr == 0: - # 翻译接收者表达式(求值结果应为 Ptr(Struct)) - expr_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, expr_method_at.value, funcs_ptr, func_count, trans) - if expr_obj is not None and expr_obj.Ty is not None: - expr_cls_nm: str = None - # 递归解 Ptr:识别 X|t.CPtr 联合简化的 Ptr(Ptr(Struct)) - # (如 (a*2.0 - b) 中 __mul__ 返回 Vec3**),否则方法 - # 调用被当裸函数 @dot 解析 → 链接 undefined symbol - expr_struct_ty: llvmlite.LLVMType | t.CPtr = \ - HandlesStruct.get_struct_type_from_value(expr_obj) - if expr_struct_ty is not None: - expr_cls_nm = HandlesStruct.get_class_name_by_type( - pool, expr_struct_ty) - # 回退:LLVM 类型为 Ptr(i8)(方法返回 X|t.CPtr 无类型信息)时, - # 从接收者表达式结构推断类名(链式调用 c2.scale(2.0).move(...) - # 的 scale 返回 Ptr(i8),经 infer_expr_class → vpi 返回注解) - # 跨 Mixin 不能 self 调用 ExprGenMixin 方法,经全局单例 - if expr_cls_nm is None: - import lib.core.Gen.Generator as Generator - g3: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g3 is not None: - expr_cls_nm = g3.infer_expr_class( - pool, mod, expr_method_at.value, trans) - if expr_cls_nm is not None: - # 值类型接收者(内嵌 struct 字段,如 zdeflate s.writer 值字段): - # 方法调用 self 必须传字段地址(GEP)而非 load 出的结构体值, - # 否则结构体值(40B)塞进 zbit_writer* 参数 → ABI 错配 → - # 被调方把值当 this 指针解引用 → GEP 0x18 崩溃 - # (s.writer.write_zlib_header 运行时 access-violation 根因; - # 本路径 evk=Attribute 先于 self.field.method() 分支命中)。 - expr_is_ptr: int = 0 - match expr_obj.Ty: - case llvmlite.LLVMType.Ptr(expr_ptr_inner): - expr_is_ptr = 1 - case _: - expr_is_ptr = 0 - if expr_is_ptr == 0: - expr_addr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( - builder, pool, mod, expr_method_at.value, trans) - if expr_addr is not None: - expr_obj = expr_addr - 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 = HandlesExprCall._translate_fakeduck_call( - pool, builder, mod, None, func_name, cl, trans) - if fd_expr_res is not None: - return fd_expr_res - - # ============================================================ - # 检测 self.field.method() 调用 - # - # 当 method_at.value 是 Attribute(字段访问,如 self.__pool__)时, - # 翻译字段值获取对象指针,然后走方法调用路径。 - # - # 路径1: 从字段值的 LLVM 类型获取类名(字段类型为 Ptr(Struct("MemManager"))) - # 路径2: 从字段的 AnnotClassName 回退查找(字段类型被简化为 Ptr(i8) 时) - # ============================================================ - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - attr_method_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if attr_method_at is not None and attr_method_at.value is not None: - if attr_method_at.value.kind() == ast.ASTKind.Attribute and trans is not None: - inner_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(attr_method_at.value) - if inner_attr is not None and inner_attr.attr is not None: - # 翻译 self.__pool__ 获取字段值(已 load 的对象指针) - field_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, attr_method_at.value, funcs_ptr, func_count, trans) - if field_obj is not None and field_obj.Ty is not None: - field_cls_nm: str = None - # 路径1: 从字段值的 LLVM 类型获取类名 - match field_obj.Ty: - case llvmlite.LLVMType.Ptr(field_struct_ty): - field_cls_nm = HandlesStruct.get_class_name_by_type( - pool, field_struct_ty) - # 路径2: 从字段注解类名回退查找 - if field_cls_nm is None: - if inner_attr.value is not None and inner_attr.value.kind() == ast.ASTKind.Name: - inner_name_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner_attr.value) - if inner_name_node is not None and inner_name_node.id is not None: - inner_var: llvmlite.Value | t.CPtr = HandlesVar.lookup_var( - trans.SymTab, inner_name_node.id) - if inner_var is not None and inner_var.Ty is not None: - match inner_var.Ty: - case llvmlite.LLVMType.Ptr(field_owner_struct_ty): - field_info: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field( - field_owner_struct_ty, inner_attr.attr) - if field_info is not None: - field_annot: str = HandlesStruct.get_field_annot_class_name(field_info) - if field_annot is not None: - dot_p: str = string.strrchr(field_annot, 46) - if dot_p is not None: - field_cls_nm = dot_p + 1 - else: - field_cls_nm = field_annot - if field_cls_nm is not None: - # 值类型字段(内嵌 struct,如 zdeflate_stream.writer: zbit_writer) - # 方法调用 self 必须传字段地址(GEP),而非 load 出的结构体值: - # 传值给 stub 声明/define 的 zbit_writer* 参数 → ABI 错配, - # 被调方把结构体值前 8 字节当 this 指针解引用 → GEP 0x18 崩溃 - # (zdeflate s.writer.write_zlib_header 运行时 access-violation 根因)。 - is_val_field: int = 0 - match field_obj.Ty: - case llvmlite.LLVMType.Ptr(field_ptr_inner): - is_val_field = 0 - case _: - is_val_field = 1 - if is_val_field != 0: - field_addr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr( - builder, pool, mod, attr_method_at.value, trans) - if field_addr is not None: - field_obj = field_addr - return HandlesExprCall._translate_method_call( - pool, builder, mod, field_cls_nm, func_name, - field_obj, cl, trans) - - # ============================================================ - # 检测 list 内置方法调用: lst.get(i), lst.set(i,v), lst.pop(), lst.clear(), lst.__iter__() - # list[T] 是泛型类不注册 struct,方法调用处理器(上方)无法处理, - # 需要在此特殊处理。 - # list 结构布局 (6 字段 × 8 字节): - # __data__(0) __count__(8) __capacity__(16) __pool__(24) __elem_size__(32) __iter_index__(40) - # ============================================================ - if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: - lm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func) - if lm_at is not None and lm_at.attr is not None and lm_at.value is not None: - lm_name: str = lm_at.attr - # 判断是否是 list 方法名 - lm_is_list: int = 0 - if string.strcmp(lm_name, "get") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "__getitem__") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "set") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "__setitem__") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "pop") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "clear") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "__iter__") == 0: lm_is_list = 1 - elif string.strcmp(lm_name, "append") == 0: lm_is_list = 1 - - if lm_is_list == 1 and trans is not None: - # 翻译 list 对象 - lm_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, lm_at.value, funcs_ptr, func_count, trans) - if lm_obj is not None: - # 防御性类型检查: lm_obj 必须是指针类型才能做 GEP - # translate_value 对某些 Attribute 节点(如 ast.Arguments 的属性) - # 可能返回 i32 0 (非指针),直接 GEP 会导致 - # "base of getelementptr must be a pointer" 错误 - if lm_obj.Ty is None or HandlesExpr.is_ptr_type(lm_obj.Ty) == 0: - # translate_value 类型推断失败(目标对象非指针): - # fail-fast,绝不 VLogger.critical 后 return None 静默吞掉 - HandlesType.fatal_error( - lm_at.value, f"list 方法 '{lm_name}' 目标对象非指针", "TypeError") - i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool) - i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool) - i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty) - # 元素类型 T:从 list 特化类型名解析(list[int]→i32、 - # list[str]→i8*、未知/指针元素→i8*)。此前 get/set/pop - # 固定 i8*(8 字节)读写:set 的 8 字节 store 覆盖相邻元素 - # (inttoptr 值,如 set(1,99) 把 data[8..11] 的 30 清 0), - # pop 读回 0 → ListTest "pop FAILED expect 30" 根因。 - # subscript 路径(list_getitem_inline 调用方)已用 - # _list_elem_type_from_name 修正,方法调用路径漏改。 - lm_esty: llvmlite.LLVMType | t.CPtr = \ - HandlesStruct.get_struct_type_from_value(lm_obj) - lm_ename: str = None - if lm_esty is not None: - lm_ename = llvmlite.get_struct_name(lm_esty) - lm_elem_ty: llvmlite.LLVMType | t.CPtr = None - if lm_ename is not None: - import lib.core.Gen.Generator as Generator - g_le: Generator.Generator | t.CPtr = ( - Generator.Generator | t.CPtr)( - t.CVoid(HandlesExpr._g_gen, t.CPtr)) - if g_le is not None: - lm_elem_ty = g_le._list_elem_type_from_name( - pool, lm_ename) - if lm_elem_ty is None: - lm_elem_ty = i8_ptr_ty - - # get / __getitem__: 返回 index 处的元素 - if string.strcmp(lm_name, "get") == 0 or string.strcmp(lm_name, "__getitem__") == 0: - if can >= 1: - # 加载 __data__ (偏移 0) - g_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - g_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx0) - g_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, g_dpp) - # 加载 __elem_size__ (偏移 32, index 4) - g_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - g_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, g_idx4) - g_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, g_epp) - # 翻译 index - g_idx_node: ast.AST | t.CPtr = cargs.get(0) - g_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, g_idx_node, None, 0, trans) - if g_data is not None and g_esize is not None and g_idx_val is not None: - g_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, g_idx_val, i64_ty, g_idx_node) - g_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, g_idx_i64, g_esize) - g_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, g_data, g_offset) - if g_addr is not None: - g_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, g_addr, llvmlite.Ptr(pool, lm_elem_ty)) - if g_ep is not None: - return llvmlite.build_load(builder, lm_elem_ty, g_ep) - - # set / __setitem__: 设置 index 处的元素 - elif string.strcmp(lm_name, "set") == 0 or string.strcmp(lm_name, "__setitem__") == 0: - if can >= 2: - s_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - s_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx0) - s_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, s_dpp) - s_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - s_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, s_idx4) - s_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, s_epp) - s_idx_node: ast.AST | t.CPtr = cargs.get(0) - s_val_node: ast.AST | t.CPtr = cargs.get(1) - s_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, s_idx_node, None, 0, trans) - s_val_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, s_val_node, None, 0, trans) - if s_data is not None and s_esize is not None and s_idx_val is not None and s_val_val is not None: - s_idx_i64: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, s_idx_val, i64_ty, s_idx_node) - s_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, s_idx_i64, s_esize) - s_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s_data, s_offset) - if s_addr is not None: - s_val_elem: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type( - builder, s_val_val, lm_elem_ty, s_val_node) - s_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, s_addr, llvmlite.Ptr(pool, lm_elem_ty)) - if s_ep is not None: - llvmlite.build_store(builder, s_val_elem, s_ep) - return None - - # pop: 返回最后一个元素,count-- - elif string.strcmp(lm_name, "pop") == 0: - p_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - p_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx1) - p_count: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_cpp) - p_nc: llvmlite.Value | t.CPtr = llvmlite.build_sub( - builder, p_count, llvmlite.const_int64(pool, 1)) - llvmlite.build_store(builder, p_nc, p_cpp) - p_idx0: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 0) - p_dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx0) - p_data: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, p_dpp) - p_idx4: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 4) - p_epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, p_idx4) - p_esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, p_epp) - if p_data is not None and p_esize is not None and p_nc is not None: - p_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, p_nc, p_esize) - p_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, p_data, p_offset) - if p_addr is not None: - p_ep: llvmlite.Value | t.CPtr = llvmlite.build_bitcast( - builder, p_addr, llvmlite.Ptr(pool, lm_elem_ty)) - if p_ep is not None: - return llvmlite.build_load(builder, lm_elem_ty, p_ep) - - # clear: count = 0 - elif string.strcmp(lm_name, "clear") == 0: - c_idx1: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1) - c_cpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, c_idx1) - llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), c_cpp) - return None - - # __iter__: iter_index = 0, return self - elif string.strcmp(lm_name, "__iter__") == 0: - it_idx5: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 5) - it_ipp: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i64_ty, lm_obj, it_idx5) - llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), it_ipp) - return lm_obj - - # append: 直接调用 list.append(self, item) - # append 需要容量检查和内存重分配,逻辑复杂,直接调用 _list.py 中的实现 - elif string.strcmp(lm_name, "append") == 0: - if can >= 1: - ap_sha1: str = self._lookup_module_sha1("_list") - if ap_sha1 is None: - # 依赖模块未编译(_list 未预加入编译链):fail-fast, - # 绝不静默跳过 append(元素永远不会被加入列表) - HandlesType.fatal_error( - cl, "list.append: 找不到 _list 模块 SHA1(依赖模块未编译)", - "InternalCompilerError") - if ap_sha1 is not None: - # 特化类名提取:list.append 的符号名是 - # {sha1}.list[AST|CPtr].append(带类型参数特化名), - # 而非 {sha1}.list.append。lm_obj 类型即特化结构体 - # Ptr(list[AST|CPtr]),从类型解析特化类名拼接调用名, - # 否则 ld.lld undefined symbol(定义端是特化名)。 - ap_spec_nm: str = None - ap_struct_ty: llvmlite.LLVMType | t.CPtr = \ - HandlesStruct.get_struct_type_from_value(lm_obj) - if ap_struct_ty is not None: - ap_spec_nm = HandlesStruct.get_class_name_by_type( - pool, ap_struct_ty) - if ap_spec_nm is None: - ap_spec_nm = "list" - # 触发泛型特化翻译(幂等,MethodsEmitted 防重入): - # list[AST|CPtr].append 的 define 方法体在特化类翻译时 - # 生成。仅构造调用名不触发特化会导致定义缺失 - # (ld.lld undefined symbol: list[AST|CPtr].append)。 - if trans is not None and ap_spec_nm is not None: - lbkt_ap: str = string.strchr(ap_spec_nm, '[') - if lbkt_ap is not None: - rbkt_ap: str = string.strrchr(ap_spec_nm, ']') - if rbkt_ap is not None and rbkt_ap > lbkt_ap: - base_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_ap) - t.CUInt64T(ap_spec_nm)) - arg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_ap) - t.CUInt64T(lbkt_ap) - 1) - if base_len_ap > 0 and arg_len_ap > 0: - base_buf_ap: str = pool.alloc(base_len_ap + 1) - arg_buf_ap: str = pool.alloc(arg_len_ap + 1) - if base_buf_ap is not None and arg_buf_ap is not None: - string.strncpy(base_buf_ap, ap_spec_nm, base_len_ap) - base_buf_ap[base_len_ap] = '\0' - string.strncpy(arg_buf_ap, lbkt_ap + 1, arg_len_ap) - arg_buf_ap[arg_len_ap] = '\0' - args_ap: list[str] | t.CPtr = list[str](pool, 8) - if args_ap is not None: - # 逗号分隔多类型实参(list[X] / dict[K, V]) - cur_ap: str = arg_buf_ap - while cur_ap is not None: - comma_ap: str = string.strchr(cur_ap, ',') - if comma_ap is None: - args_ap.append(cur_ap) - break - seg_len_ap: t.CSizeT = t.CSizeT(t.CUInt64T(comma_ap) - t.CUInt64T(cur_ap)) - seg_buf_ap: str = pool.alloc(seg_len_ap + 1) - if seg_buf_ap is not None: - string.strncpy(seg_buf_ap, cur_ap, seg_len_ap) - seg_buf_ap[seg_len_ap] = '\0' - args_ap.append(seg_buf_ap) - cur_ap = comma_ap + 1 - HandlesClassDef._specialize_generic_class( - trans, base_buf_ap, args_ap) - # 调用名 "{sha1}.{spec}.append": - # sha1(16) + '.'(1) + spec + '.append'(7) + NUL(1) = spec + 25。 - # 此前 +8 少 1 字节,snprintf 截断末尾 'd' → - # undefined symbol: ...list[AST|CPtr].appen(缺 d)。 - ap_mlen: t.CSizeT = string.strlen(ap_sha1) + \ - string.strlen(ap_spec_nm) + 26 - ap_mangled: str = pool.alloc(ap_mlen) - if ap_mangled is not None: - viperlib.snprintf(ap_mangled, ap_mlen, "%s.%s.append", - ap_sha1, ap_spec_nm) - ap_item_node: ast.AST | t.CPtr = cargs.get(0) - ap_item_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value( - builder, pool, mod, ap_item_node, None, 0, trans) - if ap_item_val is not None: - llvmlite.value_set_next(lm_obj, None) - llvmlite.value_set_next(ap_item_val, None) - llvmlite.value_set_next(lm_obj, ap_item_val) - ap_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool) - self._ensure_method_declare(pool, mod, ap_mangled, ap_ret_ty, lm_obj, 2) - return llvmlite.build_call(builder, ap_mangled, lm_obj, 2, ap_ret_ty, 0) + _tc_h6_method_dispatch_res: llvmlite.Value | t.CPtr = HandlesExprCall._tc_h6_method_dispatch( + pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + if _tc_h6_method_dispatch_res is not None: + return _tc_h6_method_dispatch_res # 获取关键字参数 keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords @@ -2375,7 +507,7 @@ class CallGenMixin(CallGenBase.CallGenBase): # C 库函数裸名调用支持:若模块中找不到且是已知 C 库函数,自动创建 declare # 对应 TPC 的 _C_LIB_FUNCS 机制,支持 memset/memmove/memcmp/strcmp 等裸名调用 if found_func is None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: - found_func = self._ensure_c_lib_declare(pool, mod, func_name) + found_func = HandlesExprCall._ensure_c_lib_declare(pool, mod, func_name) # builtins 自动关联:C 库未命中时,自动关联 builtins 模块的内置函数(ord/chr 等)。 # builtins 已由编译链预加入(StubMerger 预加入列表)。PhaseA 期 builtins 尚未编译, # 因此按约定签名创建 {builtins_sha1}.{name} 的 mangled declare(链接时解析到 @@ -2444,7 +576,7 @@ class CallGenMixin(CallGenBase.CallGenBase): if vpi_ret_ty is not None: call_ret_ty = vpi_ret_ty else: - call_ret_ty = self._infer_external_func_ret_ty(pool, func_name) + call_ret_ty = HandlesExprCall._infer_external_func_ret_ty(pool, func_name) # 如果模块中找不到函数,检查是否是变量(函数指针 / 闭包调用) if found_func is None: @@ -2478,7 +610,7 @@ class CallGenMixin(CallGenBase.CallGenBase): # 翻译参数并链接 # 有关键字参数且找到函数定义时,按参数名匹配 if kw_count > 0 and found_func is not None and found_params is not None: - return self._translate_call_with_kwargs( + return HandlesExprCall._translate_call_with_kwargs( pool, builder, mod, func_name, found_func, cargs, can, keywords, kw_count, trans) @@ -2512,7 +644,7 @@ class CallGenMixin(CallGenBase.CallGenBase): arg_val = decayed_fc case _: pass - ext_param_ty: llvmlite.LLVMType | t.CPtr = self._get_external_func_param_ty( + ext_param_ty: llvmlite.LLVMType | t.CPtr = HandlesExprCall._get_external_func_param_ty( pool, func_name, ai) if ext_param_ty is not None: val_bits_ap: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty) @@ -2827,13 +959,13 @@ class CallGenMixin(CallGenBase.CallGenBase): # 直接调用 # memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失) if string.strcmp(func_name, "memcpy") == 0 and can >= 3: - return self._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2) + return HandlesExprCall._emit_llvm_memcpy_intrinsic(pool, builder, mod, mc_dst2, mc_src2, mc_num2) # 别名导入重新推断返回类型: # from X import parse as json_parse → func_name="json_parse" 时 _infer_external_func_ret_ty 返回默认 i32 # 用 orig_func_name="parse" 重新推断,能正确匹配返回 i8*(JsonValue*) # 避免指针被截断为 i32 后 inttoptr 丢失高 32 位导致崩溃 if orig_func_name is not None and orig_func_name != func_name: - re_inferred_ty: llvmlite.LLVMType | t.CPtr = self._infer_external_func_ret_ty(pool, orig_func_name) + re_inferred_ty: llvmlite.LLVMType | t.CPtr = HandlesExprCall._infer_external_func_ret_ty(pool, orig_func_name) if re_inferred_ty is not None: call_ret_ty = re_inferred_ty # ============================================================ @@ -2847,7 +979,7 @@ class CallGenMixin(CallGenBase.CallGenBase): # 仅对 mangled("{16位hex}.func")调用生效;C 库/Win32 裸名走原白名单。 # Phase 1a(declare_only)期间依赖 text.ll 未生成,保持原白名单行为不 fail-fast。 # ============================================================ - if self._is_sha1_mangled_call(call_name) != 0: + if HandlesExprCall._is_sha1_mangled_call(call_name) != 0: if trans is None or trans._declare_only == 0: cf_dot: str = string.strchr(call_name, '.') cf_last: str = string.strrchr(call_name, '.') @@ -2939,5 +1071,3 @@ class CallGenMixin(CallGenBase.CallGenBase): - - diff --git a/App/lib/core/Gen/Generator.vp b/App/lib/core/Gen/Generator.vp index e29af92..ff3d16f 100644 --- a/App/lib/core/Gen/Generator.vp +++ b/App/lib/core/Gen/Generator.vp @@ -16,6 +16,8 @@ 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.CallGenLib as CallGenLib +import lib.core.Gen.CallGenDispatch as CallGenDispatch import lib.core.Gen.FuncGenMixin as FuncGenMixin import lib.core.Gen.ClassGenMixin as ClassGenMixin import lib.core.Gen.ImportsGenMixin as ImportsGenMixin @@ -47,6 +49,7 @@ class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin, CallGenCtor.CallGenCtor, CallGenCall.CallGenCall, CallGenProp.CallGenProp, CallGenFd.CallGenFd, CallGenVt.CallGenVt, CallGenVa.CallGenVa, + CallGenLib.CallGenLib, CallGenDispatch.CallGenDispatch, 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 168f18d..25d596c 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -1869,3 +1869,115 @@ def _translate_super_call(pool: memhub.MemBuddy | t.CPtr, if g is not None: return g._translate_super_call(pool, builder, mod, cl, method_name, trans) return None + + +# ============================================================ +# translate_call 前置检测 helper(阶段 C:CallGenMixin 拆分后顶层经委托 +# 调用 CallGenDispatch 方法。每个返回 Value|CPtr,None = 未命中继续主路径) +# ============================================================ +def _tc_h1_super_ctraits(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """super()/ctraits 编译期检测(委托到 gen._tc_h1_super_ctraits)""" + 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._tc_h1_super_ctraits(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + return None + + +def _tc_h2_c_special(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """c.Deref/Asm/LLVMIR 等特殊调用(委托到 gen._tc_h2_c_special)""" + 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._tc_h2_c_special(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + return None + + +def _tc_h3_stdarg_cast(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """stdarg 糖 + str/int/bool 内置强转(委托到 gen._tc_h3_stdarg_cast)""" + 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._tc_h3_stdarg_cast(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + return None + + +def _tc_h4_type_casts(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """t.XXX / typedef 类型转换(委托到 gen._tc_h4_type_casts)""" + 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._tc_h4_type_casts(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + return None + + +def _tc_h5_sizeof_len_isinst(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """__sizeof__/len/isinstance 内置(委托到 gen._tc_h5_sizeof_len_isinst)""" + 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._tc_h5_sizeof_len_isinst(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + return None + + +def _tc_h6_method_dispatch(pool: memhub.MemBuddy | t.CPtr, + builder: llvmlite.IRBuilder | t.CPtr, + mod: llvmlite.LLVMModule | t.CPtr, + cl: ast.Call | t.CPtr, + funcs_ptr: t.CPtr, + func_count: int, + trans: HT.Translator | t.CPtr, + func_name: str, + cargs: list[ast.AST | t.CPtr] | t.CPtr, + can: t.CSizeT) -> llvmlite.Value | t.CPtr: + """静态类/方法调用/表达式接收者/self.field/list 内置(委托到 gen._tc_h6_method_dispatch)""" + 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._tc_h6_method_dispatch(pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can) + return None