1202 lines
81 KiB
Plaintext
1202 lines
81 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import stdlib
|
||
import sys
|
||
import viperlib
|
||
import w32.fileio as fileio
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Handles.HandlesBase as HandlesBase
|
||
import lib.core.Handles.HandlesTranslator as HT
|
||
import lib.core.Handles.HandlesExpr as HandlesExpr
|
||
import lib.Stub.StubMerger as StubMerger
|
||
import lib.core.Handles.HandlesExprCall as HandlesExprCall
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
import lib.Stub.StubGen.VpiReader as VpiReader
|
||
|
||
import lib.core.Gen.CallGenBase as CallGenBase
|
||
import lib.core.Handles.ExprCallTable as ExprCallTable
|
||
|
||
|
||
# ============================================================
|
||
# CallGenMixin - 调用分派 Mixin(拆分后顶层,阶段 A:底层已拆至
|
||
# CallGenBase/CallGenCBuiltin/CallGenLeafKit)
|
||
#
|
||
# 500~1500 行/文件架构重构阶段 A:底层自包含组(模块查找/返回类型解析/
|
||
# c.*/asm/llvmir/EH/isinstance/闭包/print/函数表)已拆出,本文件保留
|
||
# 调用分派中枢(translate_call 等)。继承链 CallGenMixin → LeafKit →
|
||
# CBuiltin → Base,@t.NoVTable 静态绑定沿 MRO 解析 self 调用。
|
||
#
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 常量(与 HandlesExprCall 保持一致,本地副本避免跨模块 CDefine 查找 bug)
|
||
# ============================================================
|
||
GLOBAL_FUNC_MAX: t.CDefine = 8192
|
||
GLOBAL_DEFAULTS_MAX: t.CDefine = 4096
|
||
_CEXPORT_MAX: t.CDefine = 256
|
||
ASM_MAX_OPERANDS: t.CDefine = 16
|
||
ASM_TEXT_BUF_SIZE: t.CDefine = 2048
|
||
ASM_CONST_BUF_SIZE: t.CDefine = 512
|
||
ASM_ARGS_BUF_SIZE: t.CDefine = 512
|
||
ASM_LINE_BUF_SIZE: t.CDefine = 4096
|
||
LLVMIR_MAX_OPS: t.CDefine = 16
|
||
LLVMIR_TEMPLATE_BUF: t.CDefine = 512
|
||
# 闭包名表大小(原 HandlesExprCall 模块级常量)
|
||
MAX_CLOSURE_NAMES: t.CDefine = 128
|
||
# 函数指针签名表大小(原 HandlesExprCall 模块级常量)
|
||
MAX_FUNC_PTR_SIGS: t.CDefine = 64
|
||
# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32)
|
||
ISINSTANCE_CLASS_MAX: t.CDefine = 64
|
||
|
||
|
||
# ============================================================
|
||
# CallGenMixin - 调用分派中枢(顶层,继承 LeafKit)
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class CallGenMixin(CallGenBase.CallGenBase):
|
||
"""调用分派 Mixin(拆分后顶层,直接继承 CallGenBase——TPV self 调用仅支持 1 级父类)"""
|
||
|
||
# ============================================================
|
||
# 翻译函数调用 Call(func, args) — 模块级版本
|
||
# ============================================================
|
||
def translate_call(self, pool: memhub.MemBuddy | t.CPtr,
|
||
builder: llvmlite.IRBuilder | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
node: ast.AST | t.CPtr,
|
||
funcs_ptr: t.CPtr,
|
||
func_count: int,
|
||
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
|
||
"""翻译函数调用,返回 call 结果 Value"""
|
||
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
|
||
if cl is None:
|
||
return None
|
||
|
||
func_name: str = self.Gen.ExprGenBase.get_func_name(cl.func)
|
||
|
||
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
can: t.CSizeT = 0
|
||
if cargs is not None:
|
||
can = len(cargs)
|
||
|
||
# super()/ctraits 检测:void 方法(如 __init__)命中后 build_call 返回
|
||
# None 属预期(void call 无 SSA 值),必须用 hit_box 区分"命中已处理"
|
||
# 与"未命中",否则 None 被误判继续主路径 → 内层 Call(super) 当裸名
|
||
# 调用报"super 未定义且未导入"(SuperTest 根因)。
|
||
h1_hit: t.CPtr = stdlib.malloc(4)
|
||
if h1_hit is not None:
|
||
h1_hit[0] = 0
|
||
_tc_h1_super_ctraits_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h1_super_ctraits(
|
||
pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h1_hit)
|
||
h1_hit_val: int = 0
|
||
if h1_hit is not None:
|
||
h1_hit_val = h1_hit[0]
|
||
stdlib.free(h1_hit)
|
||
if _tc_h1_super_ctraits_res is not None:
|
||
return _tc_h1_super_ctraits_res
|
||
if h1_hit_val != 0:
|
||
# 命中 super()/ctraits 但无返回值(void 方法/宏调用):视为已处理
|
||
return None
|
||
|
||
# ---- func_name is None:泛型实例化 + 类型转换 ----
|
||
if func_name is None:
|
||
# 检查是否是 list[int](pool) 形式的泛型实例化调用
|
||
# Subscript 节点作为 Call func: 泛型类构造函数
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Subscript and trans is not None:
|
||
sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(cl.func)
|
||
if sub_node.value is not None and sub_node.value.kind() == ast.ASTKind.Name:
|
||
gen_nm_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_node.value)
|
||
gen_class_name: str = gen_nm_node.id
|
||
# 检查是否是泛型类模板
|
||
template_cd: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(gen_class_name)
|
||
if template_cd is not None:
|
||
# 提取类型实参
|
||
gen_type_args: list[str] | t.CPtr = self.Gen.CallGenCtor._extract_type_args_from_slice(pool, sub_node.slice)
|
||
if gen_type_args is not None and len(gen_type_args) > 0:
|
||
# 特化泛型类,返回特化类名
|
||
spec_name: str = self.Gen.ClassGenGeneric._specialize_generic_class(
|
||
trans, gen_class_name, gen_type_args)
|
||
if spec_name is not None:
|
||
# 泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__
|
||
# 不能直接用 spec_name 作为 func_name(会走裸名调用路径,
|
||
# 被 star import 回退误导用错误的 SHA1,且缺少 __new__ 方法名后缀)
|
||
return self.Gen.CallGenCtor._translate_generic_ctor_call(
|
||
pool, builder, mod, spec_name, cl, trans)
|
||
else:
|
||
# 泛型类模板未找到:可能是泛型函数手动传类型参数调用 xxx[T](x)
|
||
# (对应 TPC _HandleGenericCallExplicitLlvm;TPV 无泛型函数特化,
|
||
# 泛型函数按普通函数编译,类型参数 [T] 仅在函数定义处消费)。
|
||
# 检查当前模块是否已定义同名函数(def double[T] 编译后即普通函数
|
||
# double),若是则丢弃 [t.CInt] 显式类型参数,退回普通函数调用。
|
||
if self.find_func_in_module(mod, gen_class_name) is not None:
|
||
func_name = gen_class_name
|
||
else:
|
||
# 泛型类模板未找到:可能未 import 定义模块
|
||
gt_err: str = pool.alloc(256)
|
||
if gt_err is not None:
|
||
viperlib.snprintf(gt_err, 256, "泛型类 '%s' 未找到模板,可能未 import 定义模块", gen_class_name)
|
||
self.Gen.TypeGenErr.fatal_error(gen_nm_node, gt_err)
|
||
self.Gen.TypeGenErr.fatal_error(gen_nm_node, "泛型类模板未找到")
|
||
if func_name is None:
|
||
# 检查是否是 (A | t.CPtr)(value) 形式的类型转换
|
||
# BinOp 节点作为 Call func: 联合类型注解用作类型转换
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.BinOp and trans is not None:
|
||
binop_ty: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||
pool, cl.func, trans._imported_modules, trans._from_imports, trans)
|
||
if binop_ty is not None:
|
||
binop_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args
|
||
if binop_args is not None and len(binop_args) == 1:
|
||
binop_arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, binop_args.get(0), funcs_ptr, func_count, trans)
|
||
if binop_arg_val is not None:
|
||
return self.Gen.CallGenCtor._translate_t_type_cast(pool, builder, binop_arg_val, binop_ty)
|
||
return None
|
||
|
||
# c.Asm/c.LLVMIR 等特殊调用:void(无输出)时 translate_c_asm/llvmir
|
||
# 返回 None 表示"已处理无返回值",需用 hit_box 区分"未命中",
|
||
# 否则会误判未命中继续走外部函数路径(外部函数返回类型未登记 Asm +
|
||
# t.ASM_DESCR 被当 CDefine 常量赋值)
|
||
h2_hit: t.CPtr = stdlib.malloc(4)
|
||
if h2_hit is not None:
|
||
h2_hit[0] = 0
|
||
_tc_h2_c_special_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h2_c_special(
|
||
pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h2_hit)
|
||
h2_hit_val: int = 0
|
||
if h2_hit is not None:
|
||
h2_hit_val = h2_hit[0]
|
||
stdlib.free(h2_hit)
|
||
if _tc_h2_c_special_res is not None:
|
||
return _tc_h2_c_special_res
|
||
if h2_hit_val != 0:
|
||
# 命中 c.Asm/c.LLVMIR 但无返回值(void):视为已处理
|
||
return None
|
||
|
||
_tc_h3_stdarg_cast_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._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
|
||
|
||
_tc_h4_type_casts_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._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
|
||
|
||
_tc_h5_sizeof_len_isinst_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._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
|
||
|
||
# c.Asm/c.LLVMIR 等方法调用分派:方法调用识别成功但返回 None
|
||
# (如编译器生成方法 __before_init__/__init__ 恒返回 void,_translate_
|
||
# method_call 或 _emit_eh_guarded_call 处理后可能返回 None)时,须用
|
||
# hit_box 区分"已识别为方法调用"与"未命中",否则 translate_call 误判
|
||
# 未命中继续走跨模块函数路径,把对象名当模块名查 SHA1 →
|
||
# "跨模块调用 'buf.__before_init__' 找不到模块 SHA1"(memhub.alloc_buf 根因)。
|
||
h6_hit: t.CPtr = stdlib.malloc(4)
|
||
if h6_hit is not None:
|
||
h6_hit[0] = 0
|
||
_tc_h6_method_dispatch_res: llvmlite.Value | t.CPtr = self.Gen.CallGenDispatch._tc_h6_method_dispatch(
|
||
pool, builder, mod, cl, funcs_ptr, func_count, trans, func_name, cargs, can, h6_hit)
|
||
h6_hit_val: int = 0
|
||
if h6_hit is not None:
|
||
h6_hit_val = h6_hit[0]
|
||
stdlib.free(h6_hit)
|
||
if _tc_h6_method_dispatch_res is not None:
|
||
return _tc_h6_method_dispatch_res
|
||
if h6_hit_val != 0:
|
||
# 命中方法调用路径但无返回值(编译器生成方法等 void 语义):视为已处理
|
||
return None
|
||
|
||
# 获取关键字参数
|
||
keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords
|
||
kw_count: t.CSizeT = 0
|
||
if keywords is not None:
|
||
kw_count = len(keywords)
|
||
|
||
# 检查是否是结构体构造函数: Point() / Point(10, 20) / Point(x=10, y=20)
|
||
# 命名空间隔离:严格模式下检查结构体可见性
|
||
# - 裸名 Class(): 需要 from X import Class 或本地定义
|
||
# - 模块限定 Module.Class(): 需要 import Module
|
||
# 用 find_struct_by_module 规避跨模块同名 find_struct 找错
|
||
struct_ty: llvmlite.LLVMType | t.CPtr = None
|
||
gen_ctor_entry: GenTypes.StructEntry | t.CPtr = None
|
||
vis: int = self.Gen.StructGen.is_struct_visible(func_name)
|
||
if vis != 0:
|
||
if trans is not None:
|
||
gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, trans.ModuleSha1)
|
||
if gen_ctor_entry is None:
|
||
gen_ctor_entry = self.Gen.StructGen.find_struct(func_name)
|
||
if gen_ctor_entry is not None:
|
||
struct_ty = gen_ctor_entry.Ty
|
||
elif trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||
at_qc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Name:
|
||
mod_nm_qc: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_qc.value)
|
||
imp_ok: int = self.Gen.ImportsGen.is_module_imported(trans._imported_modules, mod_nm_qc.id)
|
||
if imp_ok != 0:
|
||
if trans is not None:
|
||
gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(func_name, trans.ModuleSha1)
|
||
if gen_ctor_entry is None:
|
||
gen_ctor_entry = self.Gen.StructGen.find_struct(func_name)
|
||
if gen_ctor_entry is not None:
|
||
struct_ty = gen_ctor_entry.Ty
|
||
elif at_qc.value is not None and at_qc.value.kind() == ast.ASTKind.Attribute:
|
||
# 多层模块路径类构造: w32.fileio.File(...)(value 是嵌套 Attribute)。
|
||
# 仅两层(fileio.File)支持时,三层会被跳过 → 退化走跨模块普通函数
|
||
# 调用生成 @File 裸名 → 链接 undefined symbol: File(SysLibTest 根因)。
|
||
# 模块路径经 attr_module_path_str 递归拼接("w32.fileio"),
|
||
# import 检查用完整路径(import w32.fileio 注册 "w32.fileio"),
|
||
# 结构体查找用该模块自身 SHA1 精确命中(find_struct_by_module)。
|
||
# 注:经 HandlesExpr 委托调用(跨 mixin 不能 self. 直接调,
|
||
# @t.NoVTable 静态绑定会 mangle 成 CallGenMixin. 前缀 → undefined reference)。
|
||
mod_path_qc: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, at_qc.value)
|
||
if mod_path_qc is not None:
|
||
imp_ok_qc: int = self.Gen.ImportsGen.is_module_imported(
|
||
trans._imported_modules, mod_path_qc)
|
||
if imp_ok_qc != 0:
|
||
mod_sha1_qc: str = self._lookup_module_sha1(mod_path_qc)
|
||
if mod_sha1_qc is not None:
|
||
gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(
|
||
func_name, mod_sha1_qc)
|
||
if gen_ctor_entry is None:
|
||
gen_ctor_entry = self.Gen.StructGen.find_struct(func_name)
|
||
if gen_ctor_entry is not None:
|
||
struct_ty = gen_ctor_entry.Ty
|
||
# 别名导入的类构造: from X import Class as Alias → Alias(args)
|
||
# 可见性列表按别名注册(HandleImportFromNames 用 local_name=asname),但结构体
|
||
# 按原名注册(如 Keyword as KwNode → 可见 "KwNode"、注册名 "Keyword")。
|
||
# 直接按别名 find_struct 查不到 → 误走普通函数路径生成 @sha1.Keyword 调用
|
||
# (该函数不存在)→ 链接期 undefined reference。此处解析别名→原名再查结构体。
|
||
if gen_ctor_entry is None and trans is not None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||
if trans._from_imports is not None:
|
||
ctor_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0)
|
||
if ctor_sha1 is not None:
|
||
ctor_orig: str = self.Gen.ImportsGen.lookup_from_import_original(
|
||
trans._from_imports, func_name)
|
||
if ctor_orig is not None:
|
||
# 复制到独立 null 终止缓冲区(from_imports 内部缓冲未终止)
|
||
co_len: t.CSizeT = 0
|
||
while ctor_orig[co_len] != ' ' and ctor_orig[co_len] != '\0':
|
||
co_len += 1
|
||
co_buf: str = pool.alloc(co_len + 1)
|
||
if co_buf is not None:
|
||
for co_i in range(co_len):
|
||
co_buf[co_i] = ctor_orig[co_i]
|
||
co_buf[co_len] = '\0'
|
||
# 原名结构体查找(可见性已由别名保证,原名无需再查)
|
||
gen_ctor_entry = self.Gen.StructGen.find_struct_by_module(co_buf, ctor_sha1)
|
||
if gen_ctor_entry is None:
|
||
gen_ctor_entry = self.Gen.StructGen.find_struct(co_buf)
|
||
if gen_ctor_entry is not None:
|
||
struct_ty = gen_ctor_entry.Ty
|
||
func_name = co_buf
|
||
if struct_ty is not None:
|
||
if can == 0 and kw_count == 0:
|
||
# OOP 结构体:即使无参数也调用 __before_init__
|
||
# 用 gen_ctor_entry 规避跨模块同名 find_struct 找错
|
||
ctor_is_oop: int = 0
|
||
if gen_ctor_entry is not None:
|
||
ctor_is_oop = gen_ctor_entry.IsOOP
|
||
if ctor_is_oop != 0:
|
||
return self.Gen.CallGenCtor._translate_struct_ctor(
|
||
pool, builder, mod, struct_ty, func_name, cargs, 0, trans)
|
||
# @t.NoVTable 类(无方法、类语义/指针对象):无参构造也应分配内存
|
||
# 返回指针。否则按值结构体返回 ConstZero(struct_ty),LHS 联合注解
|
||
# (如 Plain|CPtr)存 0 指针 → p.v 解引用 NULL 段错误
|
||
# (TpvIsinstanceTest Plain 场景崩溃根因)。
|
||
ctor_is_novt: int = 0
|
||
if gen_ctor_entry is not None:
|
||
ctor_is_novt = gen_ctor_entry.IsNoVTable
|
||
if ctor_is_novt != 0:
|
||
return self.Gen.CallGenCtor._translate_struct_ctor(
|
||
pool, builder, mod, struct_ty, func_name, cargs, 0, trans)
|
||
# 普通结构体:检查是否有默认值(用 entry 直接访问)
|
||
gen_has_defaults: int = 0
|
||
if gen_ctor_entry is not None:
|
||
for gdi in range(gen_ctor_entry.FieldCount):
|
||
gdf: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry(
|
||
gen_ctor_entry, gdi)
|
||
if gdf is not None and gdf.DefaultVal is not None:
|
||
gen_has_defaults = 1
|
||
break
|
||
else:
|
||
gen_has_defaults = self.Gen.StructGen.struct_has_defaults(func_name)
|
||
if gen_has_defaults == 1:
|
||
# 有默认值:走构造函数路径应用默认值
|
||
return self.Gen.CallGenCtor._translate_struct_ctor(
|
||
pool, builder, mod, struct_ty, func_name, cargs, 0, trans)
|
||
# 无默认值:返回 zeroinitializer
|
||
ret: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty)
|
||
return ret
|
||
if kw_count > 0:
|
||
# 有关键字参数:按字段名赋值
|
||
return self.Gen.CallGenCtor._translate_struct_ctor_kw(
|
||
pool, builder, mod, struct_ty, func_name, cargs, can,
|
||
keywords, kw_count, trans)
|
||
# 仅位置参数:按字段顺序构建
|
||
return self.Gen.CallGenCtor._translate_struct_ctor(
|
||
pool, builder, mod, struct_ty, func_name, cargs, can, trans)
|
||
|
||
# 裸名泛型类模板构造: Box(42) → 从实参推断类型实参 → 特化 → 构造
|
||
# (TPC 参考: _HandleGenericClassNewLlvm;GenericTest Test4 Box(42)/Test5
|
||
# Pair(10,20)/Test10 Counter(0) 依赖此路径。显式类型实参 list[int](mb)
|
||
# 走 translate_call 上方的 Subscript 分支,此处处理裸名 + 推断。)
|
||
# 支持模块限定调用(vector.Vector(...)):func_name 是 attr("Vector"),
|
||
# 需确认模块已导入(模板查找兜底——普通函数如 stdlib.free 的 attr 找
|
||
# 不到模板 → 回落普通调用)。
|
||
if struct_ty is None and gen_ctor_entry is None and trans is not None:
|
||
is_gen_bare: int = 0
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||
is_gen_bare = 1
|
||
elif cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||
at_gb: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if at_gb.value is not None and at_gb.value.kind() == ast.ASTKind.Name:
|
||
am_gb: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_gb.value)
|
||
if am_gb.id is not None:
|
||
if self.Gen.ImportsGen.is_module_imported(trans._imported_modules, am_gb.id) != 0:
|
||
is_gen_bare = 1
|
||
if is_gen_bare != 0:
|
||
template_cd_bare: ast.ClassDef | t.CPtr = self.Gen.ClassGenGeneric._find_generic_template(func_name)
|
||
if template_cd_bare is not None and template_cd_bare.type_params is not None:
|
||
tp_bare: list[str] | t.CPtr = template_cd_bare.type_params
|
||
tp_count_bare: t.CSizeT = len(tp_bare)
|
||
if tp_count_bare > 0:
|
||
inferred_args_bare: list[str] | t.CPtr = list[str](pool, 8)
|
||
if inferred_args_bare is not None:
|
||
# 对齐 TPC _HandleGenericClassNewLlvm:先收集全部实参
|
||
# 推断类型,过滤纯 int(排除 pool 等非 T 参数),
|
||
# hint_types 优先填充(Vector(pool,8,CFloat64T(0.0))
|
||
# → Vector[double];Vector(pool,10,CInt(0)) → Vector[int])
|
||
hint_bare: list[str] | t.CPtr = list[str](pool, 8)
|
||
if hint_bare is not None:
|
||
hi_bare: t.CSizeT
|
||
for hi_bare in range(can):
|
||
hty_bare: str = self.Gen.CallGenCtor._infer_generic_ctor_type_arg(pool, cargs.get(hi_bare), func_name)
|
||
if string.strcmp(hty_bare, "int") != 0:
|
||
hint_bare.append(hty_bare)
|
||
tpi_bare: t.CSizeT = 0
|
||
for tpi_bare in range(tp_count_bare):
|
||
ta_bare: str = "int"
|
||
if tpi_bare < len(hint_bare):
|
||
ta_bare = hint_bare.get(tpi_bare)
|
||
elif tpi_bare < can:
|
||
ta_bare = self.Gen.CallGenCtor._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare), func_name)
|
||
inferred_args_bare.append(ta_bare)
|
||
spec_name_bare: str = self.Gen.ClassGenGeneric._specialize_generic_class(
|
||
trans, func_name, inferred_args_bare)
|
||
if spec_name_bare is not None:
|
||
return self.Gen.CallGenCtor._translate_generic_ctor_call(
|
||
pool, builder, mod, spec_name_bare, cl, trans)
|
||
|
||
# REnum 变体构造检测: ClassName.VariantName(args...)
|
||
# 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体
|
||
# 必须在跨模块调用查找之前,否则 ClassName 会被误判为模块名
|
||
# 对应 TPC HandlesExprCall.py:585-644 的三条检测路径之一
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||
rc_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Name:
|
||
rc_cls_node: ast.Name | t.CPtr = (ast.Name | t.CPtr)(rc_at.value)
|
||
if rc_cls_node.id is not None:
|
||
rc_cls_name: str = rc_cls_node.id
|
||
# 检查 ClassName 是否是已注册的 REnum 类
|
||
if self.Gen.ClassGenEnum._is_renum_class_name(rc_cls_name) != 0:
|
||
# 在该 REnum 类中查找变体名 func_name
|
||
rc_tag: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class(
|
||
rc_cls_name, func_name)
|
||
if rc_tag >= 0:
|
||
return self.Gen.CallGenCtor._translate_renum_construct(
|
||
pool, builder, mod, rc_cls_name, func_name,
|
||
rc_tag, cargs, can, trans)
|
||
elif rc_at.value is not None and rc_at.value.kind() == ast.ASTKind.Attribute:
|
||
# 模块限定 REnum 变体构造: mod.Class.Variant(args...)
|
||
# 如 llvmlite.LLVMType.Struct(...) → 构造 llvmlite 模块 LLVMType 的 Struct 变体。
|
||
# 根因:此前只支持单层 Name(ClassName.Variant),嵌套属性漏检 → 误走跨模块
|
||
# 函数路径 → _lookup_module_sha1("llvmlite.LLVMType") 查无 → 报"跨模块调用
|
||
# 'llvmlite.LLVMType.Struct' 找不到模块 SHA1"。跨模块任意同名可接受(REnum
|
||
# 表按类名全局注册):仅要求最左模块已导入 + 末段类名在全局 REnum 表中命中,
|
||
# 不做"类必须属于该模块"校验(未命中则按后续函数路径 fast-fail)。
|
||
rc_mq_path: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, rc_at.value)
|
||
if rc_mq_path is not None:
|
||
rc_mq_dot: str = string.strrchr(rc_mq_path, 46) # 46 = ord('.')
|
||
if rc_mq_dot is not None and rc_mq_dot[1] != '\0':
|
||
# 模块路径 = 末段之前(支持多级: w32.fileio.Class.Variant)。
|
||
# 注意:不能用 rc_mq_dot - rc_mq_path 指针减法(TPC 直接发
|
||
# sub i8*, i8* 非法 IR),用 strlen 整数差扣除末段与分隔点。
|
||
rc_mq_len: t.CSizeT = string.strlen(rc_mq_path) - string.strlen(rc_mq_dot + 1) - 1
|
||
rc_mq_mod: str = pool.alloc(rc_mq_len + 1)
|
||
if rc_mq_mod is not None:
|
||
string.memcpy(rc_mq_mod, rc_mq_path, rc_mq_len)
|
||
rc_mq_mod[rc_mq_len] = '\0'
|
||
rc_mq_imp: int = 1
|
||
if trans is not None and trans._imported_modules is not None:
|
||
rc_mq_imp = self.Gen.ImportsGen.is_module_imported(
|
||
trans._imported_modules, rc_mq_mod)
|
||
if rc_mq_imp != 0:
|
||
rc_mq_cls: str = rc_mq_dot + 1
|
||
# 检查类名是否是已注册的 REnum 类
|
||
if self.Gen.ClassGenEnum._is_renum_class_name(rc_mq_cls) != 0:
|
||
rc_mq_tag: int = self.Gen.ClassGenEnum._lookup_renum_variant_in_class(
|
||
rc_mq_cls, func_name)
|
||
if rc_mq_tag >= 0:
|
||
return self.Gen.CallGenCtor._translate_renum_construct(
|
||
pool, builder, mod, rc_mq_cls, func_name,
|
||
rc_mq_tag, cargs, can, trans)
|
||
|
||
# async 裸名调用(TPV-M1/M2):普通函数调用 async 函数(如 task(5, 6))→
|
||
# 生成 create_<name>(args...) 调用(返回 Ptr(帧),bitcast 成 i8* 供变量存储)。
|
||
# 对齐 TPC HandlesAsyncFunctions._HandleAsyncCreateCallLlvm。必须在裸名
|
||
# 函数查找之前拦截——async 函数只注册了 create_/resume_,裸名 task 不在
|
||
# 函数表,走普通路径会报"裸名调用未定义且未导入"。
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||
if func_name is not None and trans is not None:
|
||
if self.Gen.AsyncGen.is_async_func(trans, func_name) != 0:
|
||
can_buf: str = pool.alloc(64)
|
||
if can_buf is not None:
|
||
viperlib.snprintf(can_buf, 64, "create_%s", func_name)
|
||
create_an: str = self.Gen.FuncGenBase._mangle_func_name(
|
||
trans, can_buf, 0)
|
||
create_fn_an: llvmlite.Function | t.CPtr = self.find_func_in_module(
|
||
mod, create_an)
|
||
if create_fn_an is not None:
|
||
frame_ty_an: llvmlite.LLVMType | t.CPtr = self.Gen.AsyncGen._lookup_coro_frame(
|
||
trans, func_name)
|
||
if frame_ty_an is not None:
|
||
ret_ptr_ty_an: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, frame_ty_an)
|
||
i8_ptr_ty_an: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
|
||
pool, llvmlite.Int8(pool))
|
||
# M2:async 调用参数(task(5, 6) → create_task(5, 6))
|
||
arg_head_an: llvmlite.Value | t.CPtr = None
|
||
arg_tail_an: llvmlite.Value | t.CPtr = None
|
||
arg_cnt_an: int = 0
|
||
if cl.args is not None:
|
||
nb_an: t.CSizeT = len(cl.args)
|
||
j_an: t.CSizeT = 0
|
||
for j_an in range(nb_an):
|
||
av_an: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, cl.args.get(j_an),
|
||
None, 0, trans)
|
||
if av_an is None:
|
||
av_an = llvmlite.const_int32(pool, 0)
|
||
av_an.Next = None
|
||
if arg_head_an is None:
|
||
arg_head_an = av_an
|
||
arg_tail_an = av_an
|
||
else:
|
||
arg_tail_an.Next = av_an
|
||
arg_tail_an = av_an
|
||
arg_cnt_an = arg_cnt_an + 1
|
||
child_an: llvmlite.Value | t.CPtr = llvmlite.build_call(
|
||
builder, create_an, arg_head_an, arg_cnt_an,
|
||
ret_ptr_ty_an, 0)
|
||
if child_an is not None:
|
||
return llvmlite.build_bitcast(builder, child_an, i8_ptr_ty_an)
|
||
return llvmlite.const_int32(pool, 0)
|
||
|
||
# 查找函数:优先从函数表按裸名精确匹配(同模块函数),
|
||
# 再从模块函数链表按后缀匹配(SHA1 前缀名)。
|
||
# 注意:模块限定/属性调用(如 stdlib.free)不能做后缀匹配——
|
||
# "free" 会误命中 viperio.Buf.free 等方法,导致普通 malloc 指针被
|
||
# 当作 Buf 对象释放(Buf.free 读 self 字段/写 self.data),
|
||
# 传入句柄数组等指针时把句柄值当地址写入直接崩溃。
|
||
# 后缀匹配仅用于裸名调用(cl.func 是 Name,如 _thread_alloc_free)。
|
||
# stubs 在翻译后才注入,翻译时跨模块函数 found_func 通常为 None,
|
||
# 此时根据函数名推断 includes 库函数的返回类型(如 strchr 返回 i8*)
|
||
# 如果调用方未传 funcs_ptr/func_count(如 AnnAssign 路径),从 trans 获取
|
||
actual_funcs: GenTypes.FuncEntry | t.CPtr = funcs_ptr
|
||
actual_func_count: int = func_count
|
||
if actual_funcs is None and trans is not None:
|
||
actual_funcs = trans._funcs
|
||
actual_func_count = trans._func_count
|
||
found_func: llvmlite.Function | t.CPtr = None
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
|
||
# 裸名调用:允许精确 + 后缀匹配
|
||
# 自定义装饰器 wrapper 重写:原函数名 → __decor_wrap_{name}
|
||
# (对齐 TPC DecoratorPass.run 的 _redirect_calls;wrapper 在函数
|
||
# 翻译末尾生成,同 pass 内 main 调用点晚于被装饰函数定义,可达)
|
||
decor_wrap_nm: str = self.Gen.ClassGenBase.lookup_decor_wrapper(func_name)
|
||
if decor_wrap_nm is not None:
|
||
found_func = self.find_func_in_module(mod, decor_wrap_nm)
|
||
else:
|
||
found_func = self.find_func_in_module(mod, func_name)
|
||
# 治本修复(对齐 Attribute 路径 L6579-6613):后缀匹配误命中类方法
|
||
# (SHA1.Class.method,第 2 段是已注册结构体类)必须拒绝——否则方法体内
|
||
# 与 from-import 模块函数同名的裸名调用(如 LLVMModuleCore.SSAValue 内
|
||
# 的 SSAValue(self.Pool, ...))绑定到本类方法 define → 无限递归
|
||
# (栈溢出 0xC0000005)。裸名调用应优先解析为模块级函数
|
||
# (同模块函数表 / from_imports),方法调用需显式 obj.method。
|
||
if found_func is not None:
|
||
bn_name: str = llvmlite.function_get_name(found_func)
|
||
if bn_name is not None:
|
||
bn_dots: int = 0
|
||
bni2: t.CSizeT = 0
|
||
while bn_name[bni2] != '\0':
|
||
if bn_name[bni2] == '.':
|
||
bn_dots += 1
|
||
bni2 += 1
|
||
if bn_dots >= 2:
|
||
# 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod)
|
||
bn_seg2: str = pool.alloc(64)
|
||
if bn_seg2 is not None:
|
||
bn_seg2[0] = '\0'
|
||
bsi2: t.CSizeT = 0
|
||
while bn_name[bsi2] != '\0' and bsi2 < 17:
|
||
bsi2 += 1
|
||
bse2: t.CSizeT = bsi2
|
||
while bn_name[bse2] != '\0' and bn_name[bse2] != '.':
|
||
bse2 += 1
|
||
bsl2: t.CSizeT = bse2 - bsi2
|
||
if bsl2 > 0 and bsl2 < 63:
|
||
string.strncpy(bn_seg2, bn_name + bsi2, bsl2)
|
||
bn_seg2[bsl2] = '\0'
|
||
# 第 2 段是已注册结构体类 → 是方法,拒绝(走模块 SHA1 路径)
|
||
if self.Gen.StructGen.get_struct_type(bn_seg2) is not None:
|
||
found_func = None
|
||
else:
|
||
# 模块限定/属性调用:精确匹配优先,后缀匹配仅接受模块函数。
|
||
# 后缀匹配命中的"方法"(SHA1.Class.method,Class 是已注册类)必须拒绝——
|
||
# 短方法名(free/reset/close 等)会误命中其他模块的方法
|
||
# (如 stdlib.free 命中 viperio.Buf.free,普通指针被当 Buf 释放崩溃;
|
||
# 且 atom.__atomic_test_and_set 若被误拒,返回类型从 i1 推断成 i32,
|
||
# 调用按 i32 读 i1 返回值读到垃圾高位,spinlock 恒非 0 卡死)。
|
||
# 模块函数(SHA1.func)或子模块函数(SHA1.submod.func)的后缀匹配保留。
|
||
found_func = self.find_func_in_module(mod, func_name)
|
||
if found_func is not None:
|
||
# 模块限定调用(mod.func,value 是已导入模块名):校验 found_func
|
||
# 的 SHA1 前缀必须等于该模块。否则 find_func_in_module 第 3 遍对
|
||
# stub declare 的后缀匹配会误命中其他模块的同名函数(如 main 模块
|
||
# 里 subprocess 的 declare 先注入,syslibtest_impl.run() 后缀匹配
|
||
# 误命中 subprocess.run → call 到错误符号 → 参数错位解引用崩溃,
|
||
# SysLibTest 0xC0000005 根因)。误命中时拒绝(found_func=None),
|
||
# 落到下方跨模块模块限定解析用模块自身 SHA1 构造正确符号。
|
||
xm_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if xm_at is not None and xm_at.value is not None and trans is not None \
|
||
and trans._imported_modules is not None:
|
||
# 模块路径:单层 Name(syslibtest_impl.run)或嵌套 Attribute
|
||
# (os._win32.exists)。后者此前不校验 → os/__init__.vp 内部
|
||
# 调 os._win32.exists 后缀匹配命中本模块同名 define →
|
||
# 无限递归栈溢出(SysLibTest 0xC00000FD 根因)。
|
||
xm_mod_path: str = None
|
||
if xm_at.value.kind() == ast.ASTKind.Name:
|
||
xm_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xm_at.value)
|
||
if xm_nm.id is not None:
|
||
xm_mod_path = xm_nm.id
|
||
elif xm_at.value.kind() == ast.ASTKind.Attribute:
|
||
xm_mod_path = self.Gen.ExprGenAttr._attr_module_path_str(
|
||
pool, xm_at.value)
|
||
if xm_mod_path is not None:
|
||
if self.Gen.ImportsGen.is_module_imported(
|
||
trans._imported_modules, xm_mod_path) != 0:
|
||
mod_sha1_chk: str = self._lookup_module_sha1(xm_mod_path)
|
||
if mod_sha1_chk is not None:
|
||
ff_nm2: str = llvmlite.function_get_name(found_func)
|
||
if ff_nm2 is not None:
|
||
if string.strncmp(ff_nm2, mod_sha1_chk, 16) != 0:
|
||
found_func = None
|
||
ff_name: str = llvmlite.function_get_name(found_func)
|
||
if ff_name is not None:
|
||
ff_dots: int = 0
|
||
ffi2: t.CSizeT = 0
|
||
while ff_name[ffi2] != '\0':
|
||
if ff_name[ffi2] == '.':
|
||
ff_dots += 1
|
||
ffi2 += 1
|
||
if ff_dots >= 2:
|
||
# 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod)
|
||
seg2: str = pool.alloc(64)
|
||
if seg2 is not None:
|
||
seg2[0] = '\0'
|
||
si: t.CSizeT = 0
|
||
while ff_name[si] != '\0' and si < 17:
|
||
si += 1
|
||
seg_start: t.CSizeT = si
|
||
seg_end: t.CSizeT = si
|
||
while ff_name[seg_end] != '\0' and ff_name[seg_end] != '.':
|
||
seg_end += 1
|
||
seg_len: t.CSizeT = seg_end - seg_start
|
||
if seg_len > 0 and seg_len < 63:
|
||
string.strncpy(seg2, ff_name + seg_start, seg_len)
|
||
seg2[seg_len] = '\0'
|
||
# 第 2 段是已注册结构体类 → 是方法,拒绝(走模块 SHA1 路径)
|
||
if self.Gen.StructGen.get_struct_type(seg2) is not None:
|
||
found_func = None
|
||
# 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.Gen.CallGenLib._ensure_c_lib_declare(pool, mod, func_name)
|
||
# builtins 自动关联:C 库未命中时,自动关联 builtins 模块的内置函数(ord/chr 等)。
|
||
# builtins 已由编译链预加入(StubMerger 预加入列表)。PhaseA 期 builtins 尚未编译,
|
||
# 因此按约定签名创建 {builtins_sha1}.{name} 的 mangled declare(链接时解析到
|
||
# builtins.vp 的真实定义);签名与 builtins.vp 保持一致:ord(i8)->i32, chr(i32)->i8。
|
||
if found_func is None:
|
||
bi_sha1: str = self._lookup_module_sha1("builtins")
|
||
if bi_sha1 is not None:
|
||
bi_ret: llvmlite.LLVMType | t.CPtr = None
|
||
bi_p1: llvmlite.LLVMType | t.CPtr = None
|
||
if string.strcmp(func_name, "ord") == 0:
|
||
bi_ret = llvmlite.Int32(pool)
|
||
bi_p1 = llvmlite.Int8(pool)
|
||
elif string.strcmp(func_name, "chr") == 0:
|
||
bi_ret = llvmlite.Int8(pool)
|
||
bi_p1 = llvmlite.Int32(pool)
|
||
if bi_ret is not None:
|
||
bi_sym: str = func_name
|
||
if self.Gen.CallGenBase.is_cexport_func(bi_sha1, func_name) == 0:
|
||
bi_sym_len: t.CSizeT = string.strlen(bi_sha1) + string.strlen(func_name) + 2
|
||
bi_sym_buf: str = pool.alloc(bi_sym_len)
|
||
if bi_sym_buf is not None:
|
||
viperlib.snprintf(bi_sym_buf, bi_sym_len, "%s.%s", bi_sha1, func_name)
|
||
bi_sym = bi_sym_buf
|
||
bi_decl: llvmlite.Function | t.CPtr = llvmlite.create_declare(
|
||
pool, mod, bi_sym, bi_ret)
|
||
if bi_decl is not None:
|
||
llvmlite.add_param(pool, bi_decl, bi_p1, "v")
|
||
found_func = bi_decl
|
||
# 使用访问器绕过 stub 类型限制
|
||
found_ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||
found_params: t.CPtr = None
|
||
if found_func is not None:
|
||
found_ret_ty = llvmlite.function_get_ret_ty(found_func)
|
||
found_params = llvmlite.function_get_params(found_func)
|
||
if found_ret_ty is not None:
|
||
call_ret_ty: llvmlite.LLVMType | t.CPtr = found_ret_ty
|
||
else:
|
||
# found_func=None(跨模块 stub 未注入):先从 vpi stub 返回注解
|
||
# 缓存精确获取返回类型(含 tuple[T1,T2] → 匿名结构体,如
|
||
# b2a_hqx -> tuple[str, t.CUnsignedShort] → {i8*, i16}),
|
||
# 未命中才回退 _infer_external_func_ret_ty 白名单推断。
|
||
# 根因:_infer 白名单无 tuple 概念,未知函数默认 i32 会截断
|
||
# 指针/i64;b2a_hqx 被推断为单值 i8*/i32 后调用侧返回值类型
|
||
# 与定义侧 {i8*, i16} 不匹配 → HandlesAssign 的 tuple 解包
|
||
# (依赖 rhs_val.Ty 是 Struct)静默跳过 → 目标变量从未赋值 →
|
||
# free 未初始化栈垃圾指针崩溃(HashLibTest hqx 段)。
|
||
vpi_ret_ty: llvmlite.LLVMType | t.CPtr = None
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||
at_ret: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if at_ret.value is not None and at_ret.value.kind() == ast.ASTKind.Name:
|
||
mod_ret_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_ret.value)
|
||
if mod_ret_nm.id is not None:
|
||
mod_ret_sha1: str = self._lookup_module_sha1(mod_ret_nm.id)
|
||
if mod_ret_sha1 is not None:
|
||
# 函数内懒 import:VpiReader imports HandlesExprCall,
|
||
# 顶层 import 会成环(与 _lookup_method_ret_ty_via_vpi 一致)
|
||
VpiReader._ensure_vpi_ret_annot_loaded(mod_ret_sha1, self.Gen.CallGenBase.TempDir)
|
||
ret_annot_fc: str = VpiReader._lookup_vpi_ret_annot(
|
||
mod_ret_sha1, None, func_name)
|
||
if ret_annot_fc is not None:
|
||
vpi_ret_ty = VpiReader._resolve_vpi_ret_annot_str(
|
||
pool, ret_annot_fc,
|
||
llvmlite.Int32(pool),
|
||
llvmlite.Ptr(pool, llvmlite.Int8(pool)))
|
||
if vpi_ret_ty is not None:
|
||
call_ret_ty = vpi_ret_ty
|
||
else:
|
||
call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, func_name)
|
||
|
||
# 如果模块中找不到函数,仅裸名调用(Name)才回退查局部变量(函数指针/
|
||
# 闭包调用);模块属性调用(VLogger.fmt_buf())的目标是模块符号,绝不
|
||
# 回退局部变量——跨模块任意同名可接受(CallGenLeafKit 局部 fmt_buf
|
||
# 曾劫持 VLogger.fmt_buf → 误走函数指针调用报 t.Callable 缺失),
|
||
# 仅 from-import 的裸名 yyy 与局部重名才可能冲突(该场景 func 是 Name)。
|
||
if found_func is None:
|
||
fp_alloca: llvmlite.Value | t.CPtr = None
|
||
if cl.func is None or cl.func.kind() == ast.ASTKind.Name:
|
||
fp_alloca = self.Gen.VarGen.lookup_var(trans.SymTab, func_name)
|
||
if fp_alloca is not None:
|
||
# 闭包变量(嵌套函数提升,已注册到闭包名集合):提取 fn_ptr/env_ptr 间接调用
|
||
if self.Gen.CallGenLeafKit.is_closure_name(func_name) != 0:
|
||
return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca,
|
||
cargs, can, trans)
|
||
# 函数指针变量(t.Callable 注解 → i8** alloca):按实参构造签名间接调用
|
||
if self.Gen.CallGenLeafKit._is_func_ptr_alloca(fp_alloca) != 0:
|
||
# 区分 t.Callable(真函数指针)vs t.CPtr(闭包指针):
|
||
# t.CPtr 变量(如 f: t.CPtr = make_counter())存的是闭包结构
|
||
# {fn_ptr, env_ptr},调用必须提取 env 传参;若按函数指针直接
|
||
# call,跳转到闭包结构数据地址崩溃(ClosureCallTest 运行时崩溃)。
|
||
ve_fp: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
|
||
trans.SymTab, func_name)
|
||
is_cptr_annot_fp: int = 0
|
||
if ve_fp is not None and ve_fp.AnnotClassName is not None:
|
||
if string.strstr(ve_fp.AnnotClassName, "CPtr") is not None:
|
||
is_cptr_annot_fp = 1
|
||
if is_cptr_annot_fp == 0:
|
||
return self.Gen.CallGenLeafKit._translate_func_ptr_call(pool, builder, mod, fp_alloca,
|
||
func_name, cargs, can, trans)
|
||
return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca,
|
||
cargs, can, trans)
|
||
# 其他 i8* 变量按闭包调用路径处理
|
||
return self.Gen.CallGenLeafKit.translate_closure_call(pool, builder, mod, fp_alloca,
|
||
cargs, can, trans)
|
||
|
||
# 翻译参数并链接
|
||
# 有关键字参数且找到函数定义时,按参数名匹配
|
||
if kw_count > 0 and found_func is not None and found_params is not None:
|
||
return self.Gen.CallGenLib._translate_call_with_kwargs(
|
||
pool, builder, mod, func_name, found_func,
|
||
cargs, can, keywords, kw_count, trans)
|
||
|
||
head: llvmlite.Value | t.CPtr = None
|
||
tail: llvmlite.Value | t.CPtr = None
|
||
# memcpy 专用: 收集前三个 Value 的独立引用(避免共享 alloca 对象的 Next 被污染)
|
||
mc_dst2: llvmlite.Value | t.CPtr = None
|
||
mc_src2: llvmlite.Value | t.CPtr = None
|
||
mc_num2: llvmlite.Value | t.CPtr = None
|
||
for ai in range(can):
|
||
arg: ast.AST | t.CPtr = cargs.get(ai)
|
||
if arg is not None:
|
||
arg_val: llvmlite.Value | t.CPtr = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, arg, None, 0, trans)
|
||
if arg_val is not None:
|
||
# 参数类型提升:当 found_func 为 None(stub 未注入)时,
|
||
# 根据外部函数签名推断期望类型,提升字面量(如 i32→i64)
|
||
# 避免 declare(i64) 与 call(i32) 类型不匹配
|
||
if found_func is None and arg_val.Ty is not None:
|
||
# 数组实参按 C 语义衰减为元素指针(对齐 TPC
|
||
# _decay_array_to_ptr),与 _translate_method_call 一致。
|
||
if self.Gen.ExprGenBase.is_ptr_type(arg_val.Ty) != 0:
|
||
arr_pointee_fc: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee
|
||
if arr_pointee_fc is not None:
|
||
match arr_pointee_fc:
|
||
case llvmlite.LLVMType.Array(arr_et_fc, _):
|
||
decayed_fc: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
|
||
builder, arr_pointee_fc, arr_et_fc, arg_val,
|
||
llvmlite.const_int32(pool, 0))
|
||
if decayed_fc is not None:
|
||
arg_val = decayed_fc
|
||
case _:
|
||
pass
|
||
ext_param_ty: llvmlite.LLVMType | t.CPtr = self.Gen.CallGenLib._get_external_func_param_ty(
|
||
pool, func_name, ai)
|
||
if ext_param_ty is not None:
|
||
val_bits_ap: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty)
|
||
tgt_bits_ap: int = self.Gen.ExprGenBase.get_llvm_type_bits(ext_param_ty)
|
||
if val_bits_ap != 0 and tgt_bits_ap != 0 and val_bits_ap != tgt_bits_ap:
|
||
if val_bits_ap == 1 and val_bits_ap < tgt_bits_ap:
|
||
arg_val = llvmlite.build_zext(builder, arg_val, ext_param_ty)
|
||
else:
|
||
arg_val = self.Gen.ExprGenBase.coerce_to_type(builder, arg_val, ext_param_ty, arg)
|
||
elif found_func is not None:
|
||
# found_func 存在:按形参类型 coerce(如 stdlib.malloc(size: t.CSizeT))
|
||
# 修复: CDefine/i32 常量传给 i64 形参未提升,导致 call(i32) 与 define(i64) 不匹配
|
||
fp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
|
||
fpi: int = 0
|
||
while fp is not None and fpi < ai:
|
||
fp = llvmlite.param_get_next(fp)
|
||
fpi += 1
|
||
if fp is not None:
|
||
fpty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fp)
|
||
if fpty is not None:
|
||
arg_val = self.Gen.ExprGenBase.coerce_to_type(
|
||
builder, arg_val, fpty, arg)
|
||
elif found_func.IsVarArg == 1:
|
||
# Win64 变参 8 字节槽位:<64 位整数按 i64 传(sext 符号扩展),
|
||
# f32 提升为 f64。若按原窄类型传,调用点只写 4 字节进 8 字节槽,
|
||
# 高 4 字节残留旧栈数据,va_arg(i64) 读到垃圾(如 DefineTest
|
||
# PAGE=%d 读到 0x400921FB00001000,高位是 PI 残留)。
|
||
# 对齐 TPC FuncGen/Python-llvmlite 的 ABI 自动提升。
|
||
ab_va: int = self.Gen.ExprGenBase.get_llvm_type_bits(arg_val.Ty)
|
||
af_va: int = self.Gen.ExprGenBase.get_llvm_float_bits(arg_val.Ty)
|
||
i64_va: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
|
||
if ab_va != 0 and ab_va < 64:
|
||
arg_val = llvmlite.build_sext(builder, arg_val, i64_va)
|
||
elif af_va == 32:
|
||
arg_val = llvmlite.build_fpext(
|
||
builder, arg_val, llvmlite.Double(pool))
|
||
arg_val.Next = None
|
||
if head is None:
|
||
head = arg_val
|
||
else:
|
||
tail.Next = arg_val
|
||
tail = arg_val
|
||
# memcpy 专用: 保存前三个参数的独立引用
|
||
if ai == 0:
|
||
mc_dst2 = arg_val
|
||
elif ai == 1:
|
||
mc_src2 = arg_val
|
||
elif ai == 2:
|
||
mc_num2 = arg_val
|
||
|
||
# 默认参数填充:当实参数量 < 形参数量时,用默认值填充缺失参数
|
||
# defaults 数组右对齐到 args:defaults[0] 对应 args[offset],offset = param_count - default_count
|
||
if can > 0 or (can == 0 and cargs is not None):
|
||
df_defaults: t.CVoid | t.CPtr = None
|
||
df_default_count: int = 0
|
||
df_param_count: int = 0
|
||
# 先从当前模块函数表查找 FuncEntry
|
||
if trans is not None and trans._funcs is not None:
|
||
df_entry: GenTypes.FuncEntry | t.CPtr = ExprCallTable.find_func_entry_in_table(
|
||
trans._funcs, trans._func_count, func_name)
|
||
if df_entry is not None:
|
||
df_defaults = df_entry.Defaults
|
||
df_default_count = df_entry.DefaultCount
|
||
df_param_count = df_entry.ParamCount
|
||
# 无条件查询全局默认参数表(跨模块/同模块都要用 stdlib 常量快照
|
||
# 重建默认值:模块表 Defaults 指向 pool 内 AST,跨 1b reset 后悬空;
|
||
# 快照才是跨文件永久存活。同模块命中时 gd_entry 也必须已赋值,
|
||
# 否则下方 _build_const_from_snapshot 读到未初始化栈垃圾指针崩溃。
|
||
# 与 _translate_method_call 的 mdf_gd 无条件查询(L2677)保持一致。
|
||
gd_entry: GenTypes.FuncDefaultsEntry | t.CPtr = self.Gen.CallGenLeafKit.find_func_defaults(func_name)
|
||
if df_defaults is None and gd_entry is not None:
|
||
df_defaults = gd_entry.Defaults
|
||
df_default_count = gd_entry.DefaultCount
|
||
df_param_count = gd_entry.ParamCount
|
||
# 填充缺失参数
|
||
if df_defaults is not None and df_default_count > 0 and can < df_param_count:
|
||
df_offset: int = df_param_count - df_default_count
|
||
df_di: int = 0
|
||
while df_di < df_default_count:
|
||
df_param_idx: int = df_offset + df_di
|
||
if df_param_idx >= can:
|
||
# 优先用 stdlib 常量快照重建(gd_entry.Defaults 的 pool 内 AST 可能已被 reset 回收)
|
||
df_arg_val: llvmlite.Value | t.CPtr = None
|
||
if gd_entry is not None:
|
||
df_arg_val = self.Gen.CallGenLeafKit._build_const_from_snapshot(
|
||
pool, mod, gd_entry, df_di, trans, builder)
|
||
if df_arg_val is None:
|
||
df_defaults_list: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(df_defaults), t.CPtr))
|
||
df_default_node: ast.AST | t.CPtr = df_defaults_list.get(df_di)
|
||
if df_default_node is not None:
|
||
df_arg_val = self.Gen.ExprGen.translate_value(
|
||
builder, pool, mod, df_default_node, None, 0, trans)
|
||
if df_arg_val is not None:
|
||
df_arg_val.Next = None
|
||
if head is None:
|
||
head = df_arg_val
|
||
else:
|
||
tail.Next = df_arg_val
|
||
tail = df_arg_val
|
||
df_di += 1
|
||
|
||
# 使用模块中的实际函数名(可能带 SHA1 前缀,如 "83210a72e829a086.atoi")
|
||
# t.CExtern/t.State/t.CExport 函数不加 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
|
||
# 原始函数名(别名导入时记录,如 from X import parse as json_parse → orig_func_name="parse")
|
||
# 用于在别名处理后重新推断返回类型,避免 _infer_external_func_ret_ty 用别名匹配失败
|
||
orig_func_name: str = None
|
||
if found_func is not None:
|
||
found_name: str = llvmlite.function_get_name(found_func)
|
||
if found_name is not None:
|
||
call_name = found_name
|
||
else:
|
||
# 跨模块函数调用:found_func 为 None 时,检查是否是模块限定调用
|
||
# 如 string.strchr(...) → @{sha1_of_string}.strchr
|
||
if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute:
|
||
xmod_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
|
||
if xmod_at.value is not None and (xmod_at.value.kind() == ast.ASTKind.Name
|
||
or xmod_at.value.kind() == ast.ASTKind.Attribute):
|
||
# 模块路径:单层 Name(string.strchr)或嵌套 Attribute
|
||
# (os._win32.exists)。嵌套路径此前不支持 → os/__init__.vp
|
||
# 内部调 os._win32.exists 只能被 find_func_in_module 后缀匹配
|
||
# 命中本模块同名 define(无限递归),或找不到模块路径而走
|
||
# 错误 fallback;此处用完整模块路径解析正确 SHA1(与校验段
|
||
# L7344 对齐,SysLibTest 0xC00000FD 根因)。
|
||
xmod_path: str = None
|
||
if xmod_at.value.kind() == ast.ASTKind.Name:
|
||
xmod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xmod_at.value)
|
||
if xmod_nm.id is not None:
|
||
xmod_path = xmod_nm.id
|
||
else:
|
||
xmod_path = self.Gen.ExprGenAttr._attr_module_path_str(pool, xmod_at.value)
|
||
if xmod_path is not None:
|
||
mod_sha1: str = self._lookup_module_sha1(xmod_path)
|
||
if mod_sha1 is not None:
|
||
# fast-fail: 模块限定调用要求模块已被当前文件 import。
|
||
# 全局 SHA1 存储包含所有被扫描的 includes,未导入的模块
|
||
# (如 this.this() 但 import this 被注释)也会命中存储,
|
||
# 静默生成 @{sha1}.func 调用而非报错——违反"找不到 fast-fail"原则。
|
||
is_xmod_imported: int = 1
|
||
if trans is not None and trans._imported_modules is not None:
|
||
is_xmod_imported = self.Gen.ImportsGen.is_module_imported(
|
||
trans._imported_modules, xmod_path)
|
||
if is_xmod_imported == 0:
|
||
err_ni: str = pool.alloc(256)
|
||
if err_ni is not None:
|
||
viperlib.snprintf(err_ni, 256,
|
||
"跨模块调用 '%s.%s':模块 '%s' 未导入(请先 import %s)",
|
||
xmod_path, func_name, xmod_path, xmod_path)
|
||
self.Gen.TypeGenErr.fatal_error(xmod_at, err_ni)
|
||
self.Gen.TypeGenErr.fatal_error(xmod_at, "跨模块调用:模块未导入")
|
||
# 检查是否是 re-export 函数(如 ast._lexer_init 实际定义在 ast.lexer)
|
||
reexport_src: str = self.Gen.ImportsGen.lookup_reexport(mod_sha1, func_name)
|
||
if reexport_src is None:
|
||
# re-export 表未命中(includes 模块 stub/text 已存在时
|
||
# 不被按需全量翻译,表只在 declare_only=0 时注册,可能为空):
|
||
# 按需解析该模块 .vpi 的 from-import 定位定义模块
|
||
reexport_src = self._lookup_reexport_from_vpi(pool, mod_sha1, func_name)
|
||
if reexport_src is not None:
|
||
reexport_sha1: str = self._lookup_module_sha1(reexport_src)
|
||
if reexport_sha1 is not None:
|
||
mod_sha1 = reexport_sha1
|
||
# CExport 函数定义用裸名(@strlen),跨模块调用需用裸名而非 @{sha1}.func
|
||
if self.Gen.CallGenBase.is_cexport_func(mod_sha1, func_name) != 0:
|
||
call_name = func_name
|
||
elif self._is_state_func_from_vpi(pool, mod_sha1, func_name) != 0:
|
||
# t.State 标记的外部 C 函数(如 CPython PyList_Size):
|
||
# 定义端用裸名 @PyList_Size(链接外部库),跨模块调用
|
||
# 必须用裸名——带 sha1 前缀 → ld.lld undefined symbol
|
||
call_name = func_name
|
||
else:
|
||
mangled_len: t.CSizeT = string.strlen(mod_sha1) + string.strlen(func_name) + 2
|
||
mangled: str = pool.alloc(mangled_len)
|
||
if mangled is not None:
|
||
viperlib.snprintf(mangled, mangled_len, "%s.%s", mod_sha1, func_name)
|
||
call_name = mangled
|
||
else:
|
||
# t 和 c 是内部库,豁免 SHA1 查找:使用裸名调用
|
||
if string.strcmp(xmod_path, "t") == 0 or string.strcmp(xmod_path, "c") == 0:
|
||
call_name = func_name
|
||
else:
|
||
# Bug 修复: 先检查是否是已导入的模块名(如 BuildPipeline.run_pipeline)
|
||
# 如果是已导入模块但 SHA1 未注册,说明该模块未被编译(如 Phase2 未扫描到),
|
||
# 应该立即报错,而不是错误地走 from_imports 查找(会被 star import 回退误导)
|
||
is_imported_mod: int = 0
|
||
if trans is not None and trans._imported_modules is not None:
|
||
is_imported_mod = self.Gen.ImportsGen.is_module_imported(
|
||
trans._imported_modules, xmod_path)
|
||
if is_imported_mod != 0:
|
||
# 别名导入(import X as Y):Y 在 _imported_modules 中,
|
||
# 但 _lookup_module_sha1("Y") 精确匹配失败(mod_arr 只存文件名)。
|
||
# 先尝试 from_imports 查找别名→完整模块名→后缀匹配 SHA1。
|
||
# allow_star_fallback=0 避免被 star import 回退误导。
|
||
alias_sha1: str = None
|
||
if trans is not None and trans._from_imports is not None:
|
||
alias_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_path, 0)
|
||
if alias_sha1 is not None:
|
||
if self.Gen.CallGenBase.is_cexport_func(alias_sha1, func_name) != 0:
|
||
call_name = func_name
|
||
elif self._is_state_func_from_vpi(pool, alias_sha1, func_name) != 0:
|
||
# t.State 外部 C 函数:裸名(同主路径 L7918)
|
||
call_name = func_name
|
||
else:
|
||
AliasMangledLen: t.CSizeT = string.strlen(alias_sha1) + string.strlen(func_name) + 2
|
||
alias_mangled: str = pool.alloc(AliasMangledLen)
|
||
if alias_mangled is not None:
|
||
viperlib.snprintf(alias_mangled, AliasMangledLen, "%s.%s", alias_sha1, func_name)
|
||
call_name = alias_mangled
|
||
else:
|
||
# 已导入模块但 SHA1 未注册:该模块未被编译,立即报错
|
||
err_msg_imp: str = pool.alloc(256)
|
||
if err_msg_imp is not None:
|
||
viperlib.snprintf(err_msg_imp, 256, "模块 '%s' 已导入但 SHA1 未注册(该模块未被编译)", xmod_path)
|
||
self.Gen.TypeGenErr.fatal_error(xmod_at, err_msg_imp)
|
||
self.Gen.TypeGenErr.fatal_error(xmod_at, "已导入模块 SHA1 未注册")
|
||
else:
|
||
# 检查是否是通过 from import 导入的名称(如 from .__types import LLVMType)
|
||
# LLVMType.Ptr(ty) 中 LLVMType 是类名不是模块名,
|
||
# 但 Ptr 是 __types 模块的模块级函数
|
||
# 禁用 star import 回退:xmod_path 是明确名称,不应回退到 star import 模块
|
||
from_sha1: str = None
|
||
if trans is not None and trans._from_imports is not None:
|
||
from_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, xmod_path, 0)
|
||
if from_sha1 is not None:
|
||
# CExport 函数定义用裸名,跨模块调用需用裸名
|
||
if self.Gen.CallGenBase.is_cexport_func(from_sha1, func_name) != 0:
|
||
call_name = func_name
|
||
else:
|
||
fmangled_len: t.CSizeT = string.strlen(from_sha1) + string.strlen(func_name) + 2
|
||
fmangled: str = pool.alloc(fmangled_len)
|
||
if fmangled is not None:
|
||
viperlib.snprintf(fmangled, fmangled_len, "%s.%s", from_sha1, func_name)
|
||
call_name = fmangled
|
||
else:
|
||
err_msg2: str = pool.alloc(256)
|
||
if err_msg2 is not None:
|
||
viperlib.snprintf(err_msg2, 256, "跨模块调用 '%s.%s' 找不到模块 SHA1", xmod_path, func_name)
|
||
self.Gen.TypeGenErr.fatal_error(xmod_at, err_msg2)
|
||
self.Gen.TypeGenErr.fatal_error(xmod_at, "跨模块调用找不到模块 SHA1")
|
||
else:
|
||
# 裸名调用(非 Attribute):检查 from_imports
|
||
# 治本修复:函数调用禁用 star import 回退(allow_star_fallback=0)。
|
||
# star import(from stdint import *)本意是导入类型/常量(如 BYTEPTR),而非函数;
|
||
# 函数应显式 from import。漏导函数若走 star 回退会被错归到 star 模块,生成错误 SHA1 符号
|
||
# (如 block_insert_text_before_terminator 漏导后被错归 stdint,生成
|
||
# f5522571bcce7bcb.block_insert... 而非 874bac141c97bae9.block_insert...)。
|
||
# 禁用回退后,漏导函数编译期即报"未定义且未导入"(fast-fail),优于链接期 undefined reference。
|
||
if trans is not None and trans._from_imports is not None:
|
||
bare_sha1: str = self._lookup_mod_sha1(pool, trans._from_imports, func_name, 0)
|
||
if bare_sha1 is not None:
|
||
# 别名处理: from X import Y as Z → 调用 Z 时需用 Y 作为源模块函数名
|
||
# 例如 from json.__parser import parse as json_parse → 修饰为 SHA1.parse 而非 SHA1.json_parse
|
||
bare_orig: str = self.Gen.ImportsGen.lookup_from_import_original(
|
||
trans._from_imports, func_name)
|
||
bare_func_name: str = func_name
|
||
if bare_orig is not None:
|
||
# bare_orig 指向 from_imports 内部缓冲区,未 null 终止
|
||
# 需复制到独立缓冲区(截断于空格或 null)
|
||
bo_len: t.CSizeT = 0
|
||
while bare_orig[bo_len] != ' ' and bare_orig[bo_len] != '\0':
|
||
bo_len += 1
|
||
bo_buf: str = pool.alloc(bo_len + 1)
|
||
if bo_buf is not None:
|
||
for bo_i in range(bo_len):
|
||
bo_buf[bo_i] = bare_orig[bo_i]
|
||
bo_buf[bo_len] = '\0'
|
||
bare_func_name = bo_buf
|
||
# 记录原始函数名,供后续重新推断返回类型
|
||
# 例如 from json.__parser import parse as json_parse
|
||
# func_name="json_parse", bare_func_name="parse"
|
||
# _infer_external_func_ret_ty 用 "parse" 能正确匹配,用 "json_parse" 则返回默认 i32
|
||
orig_func_name = bare_func_name
|
||
# re-export 解析(对齐模块限定路径 L6598):
|
||
# 裸名 from import 的函数可能实际定义在子模块(re-export)。
|
||
# 例:from ast import dump → dump 定义在 ast.base(sha1=71b2),
|
||
# ast/__init__(sha1=876e)只是 re-export。若沿用包 sha1 构造
|
||
# call_name="876e.dump",text.ll/vpi 返回类型解析均未命中,
|
||
# fail-fast 报"返回类型无法精确获取";需重定向到定义模块 SHA1。
|
||
reexport_src2: str = self.Gen.ImportsGen.lookup_reexport(bare_sha1, bare_func_name)
|
||
if reexport_src2 is None:
|
||
# re-export 表未命中:按需解析该模块 .vpi 的 from-import
|
||
reexport_src2 = self._lookup_reexport_from_vpi(pool, bare_sha1, bare_func_name)
|
||
if reexport_src2 is not None:
|
||
reexport_sha1_2: str = self._lookup_module_sha1(reexport_src2)
|
||
if reexport_sha1_2 is not None:
|
||
bare_sha1 = reexport_sha1_2
|
||
if self.Gen.CallGenBase.is_cexport_func(bare_sha1, bare_func_name) != 0:
|
||
call_name = bare_func_name
|
||
else:
|
||
bare_mangled_len: t.CSizeT = string.strlen(bare_sha1) + string.strlen(bare_func_name) + 2
|
||
bare_mangled: str = pool.alloc(bare_mangled_len)
|
||
if bare_mangled is not None:
|
||
viperlib.snprintf(bare_mangled, bare_mangled_len, "%s.%s", bare_sha1, bare_func_name)
|
||
call_name = bare_mangled
|
||
else:
|
||
err_msg3: str = pool.alloc(256)
|
||
if err_msg3 is not None:
|
||
viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name)
|
||
self.Gen.TypeGenErr.fatal_error(node, err_msg3)
|
||
self.Gen.TypeGenErr.fatal_error(node, "裸名调用未定义且未导入")
|
||
else:
|
||
err_msg4: str = pool.alloc(256)
|
||
if err_msg4 is not None:
|
||
viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name)
|
||
self.Gen.TypeGenErr.fatal_error(node, err_msg4)
|
||
self.Gen.TypeGenErr.fatal_error(node, "裸名调用未定义且未导入")
|
||
|
||
# 直接调用
|
||
# memcpy → @llvm.memcpy 内联函数(避免 monomorphization 跨模块 @memcpy 声明缺失)
|
||
if string.strcmp(func_name, "memcpy") == 0 and can >= 3:
|
||
return self.Gen.CallGenLib._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.Gen.CallGenLib._infer_external_func_ret_ty(pool, orig_func_name)
|
||
if re_inferred_ty is not None:
|
||
call_ret_ty = re_inferred_ty
|
||
# ============================================================
|
||
# 跨模块 Viper 函数返回类型精确解析(对齐方法路径,fail-fast)
|
||
# 根因:_infer_external_func_ret_ty 白名单未覆盖返回指针的模块函数
|
||
# (new_lexer→Lexer* / tokenize→Token* / parse_tokens→AST*),兜底 i32
|
||
# 导致 64 位指针被截断高 32 位 → inttoptr 无效指针 → 解引用崩溃
|
||
# (AstTest 的 _lexer_init 崩溃链)。declare 也可能是错误 i32(_ensure_method_declare
|
||
# 曾用兜底类型创建),因此不信任 found_func 的 declare 返回类型。
|
||
# 权威来源:text.ll define;次选:vpi stub 返回注解;均未命中立即终止。
|
||
# 仅对 mangled("{16位hex}.func")调用生效;C 库/Win32 裸名走原白名单。
|
||
# Phase 1a(declare_only)期间依赖 text.ll 未生成,保持原白名单行为不 fail-fast。
|
||
# ============================================================
|
||
if self.Gen.CallGenLib._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, '.')
|
||
if cf_dot is not None and cf_last is not None:
|
||
cf_sha1: str = stdlib.malloc(17)
|
||
cf_bare_len: t.CSizeT = string.strlen(call_name) - \
|
||
(t.CSizeT(t.CUInt64T(cf_last) - t.CUInt64T(call_name))) - 1
|
||
cf_bare: str = stdlib.malloc(cf_bare_len + 1)
|
||
if cf_sha1 is not None and cf_bare is not None:
|
||
string.strncpy(cf_sha1, call_name, 16)
|
||
cf_sha1[16] = '\0'
|
||
string.strcpy(cf_bare, cf_last + 1)
|
||
# 本模块自身函数(泛型特化等):从当前 IR 已声明的函数
|
||
# 取返回类型;不走跨模块 text.ll 查找——自己的 text.ll
|
||
# 在 Phase A 翻译中尚未生成,直接查会误报"依赖未生成"
|
||
# 并保持默认类型(GenericTest 泛型 add/combine 等警告
|
||
# 根因)。未命中(特化尚未声明)保持默认推断。
|
||
is_local_mod: int = 0
|
||
if trans is not None and trans.ModuleSha1 is not None:
|
||
if string.strncmp(cf_sha1, trans.ModuleSha1, 16) == 0:
|
||
is_local_mod = 1
|
||
if is_local_mod != 0:
|
||
local_fn: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name)
|
||
if local_fn is not None and local_fn.RetTy is not None:
|
||
call_ret_ty = local_fn.RetTy
|
||
else:
|
||
cf_ret: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
|
||
pool, cf_sha1, None, cf_bare, 1)
|
||
if cf_ret is not None:
|
||
call_ret_ty = cf_ret
|
||
else:
|
||
cf_vpi: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
|
||
pool, cf_sha1, None, cf_bare)
|
||
if cf_vpi is not None:
|
||
call_ret_ty = cf_vpi
|
||
else:
|
||
# 区分两种失败场景:
|
||
# 1. 依赖模块 text.ll 存在但函数未命中 → 真错误,fail-fast
|
||
# 2. 依赖模块 text.ll 不存在(模块尚未翻译)→ Phase A 按
|
||
# 文件顺序翻译,main.vp 先于其 import 的 mbuddytest.vp
|
||
# (同项目多源文件)。此时标记 trans._deps_pending=1,
|
||
# 保持白名单类型继续,Phase A 多遍循环下遍重译——
|
||
# 届时依赖已生成 text.ll,可精确解析(治本:依赖先翻译)。
|
||
if self._dep_text_ll_exists(pool, cf_sha1) != 0:
|
||
cf_err: str = VLogger.fmt_buf()
|
||
if cf_err is not None:
|
||
viperlib.snprintf(
|
||
cf_err, 1024,
|
||
"跨模块函数 '%s' 返回类型无法精确获取(text.ll/vpi 均未命中),"
|
||
"默认 i32 会截断指针/i64,请检查依赖模块是否已编译/注册", call_name)
|
||
VLogger.error(cf_err, "HandlesExprCall")
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
node,
|
||
f"跨模块函数返回类型无法精确获取(text.ll/vpi 均未命中),默认 i32 会截断指针: {call_name}",
|
||
"TypeError")
|
||
else:
|
||
if trans is not None:
|
||
trans._deps_pending = 1
|
||
cf_dbg: str = VLogger.fmt_buf()
|
||
if cf_dbg is not None:
|
||
viperlib.snprintf(
|
||
cf_dbg, 1024,
|
||
"跨模块函数 '%s' 依赖模块 text.ll 尚未生成(Phase A 顺序),"
|
||
"标记重试,本遍保持默认类型", call_name)
|
||
if VLogger.nowarn_register() == 0:
|
||
VLogger.warning(cf_dbg, "HandlesExprCall")
|
||
stdlib.free(cf_sha1)
|
||
stdlib.free(cf_bare)
|
||
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
|
||
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, can)
|
||
# 检查被调用函数是否为变长函数(*args),若是则对变长参数进行 C ABI 提升
|
||
# (cargs 为本函数参数 AST 链表,self_offset=0 普通函数调用)
|
||
is_variadic_call: int = self.Gen.CallGenVa._check_and_promote_variadic_call(
|
||
pool, builder, mod, call_name, head, can, cargs, 0, trans)
|
||
# try-except:被调函数带 EH 输出参数时,追加输出实参 + 调用后检测异常
|
||
return self.Gen.CallGenLeafKit._emit_eh_guarded_call(
|
||
builder, pool, mod, trans, found_func, call_name, head, can,
|
||
call_ret_ty, is_variadic_call)
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|