Files
ViperC/App/lib/core/Gen/CallGenMixin.vp
T
TermiNexus 120a2d7ad7 fix(Phase2): Phase A 多遍重试修复同项目依赖翻译顺序
main.vp 先于其 import 的 mbuddytest.vp 翻译(文件系统顺序),跨模块函数返回类型精确解析因依赖 text.ll 未生成而 fail-fast。新增 Translator._deps_pending + text.ll 存在性探测区分依赖未翻译/真错误,Phase A 循环改多遍,依赖就绪后下遍重译命中。
2026-08-11 01:33:52 +08:00

7496 lines
413 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
# ============================================================
# CallGenMixin - 调用分派 Mixin(对象化 P4,wiki/14-oo-refactor.md)
#
# 从 HandlesExprCall.vp(7043 行,本仓库最大文件)迁移:
# 模块级纯函数(translate_call/translate_c_*/_translate_method_call/
# _do_virtual_call/va_arg 系列/函数表/默认参数表等)→ 类方法
# 全局状态(_g_cexport_*/_g_llvmir_reg_seq/_g_temp_dir/
# _g_closure_*/_g_funcptr_*/_global_funcs/_global_defaults)→ 本类字段
#
# 迁移原则(与 P2/P3 一致,行为零变化):
# 1. 方法保留原函数签名(含 pool/builder/mod 首参),仅函数体内的
# 本模块函数调用改为 self.xxx(...)
# 2. 外部模块调用(HandlesType.xxx/HandlesExpr.xxx/StubMerger.xxx 等)
# 保留模块前缀
# 3. AsmOperand/FuncEntry/FuncDefaultsEntry 类保留在 HandlesExprCall.vp
# 4. HandlesExprCall.vp 原函数保留为"委托":本地模块级单例 _g_gen
# (BuildPipeline/main 注入)cast 成 Generator 类型
#
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
# ============================================================
# ============================================================
# 常量(与 HandlesExprCall 保持一致)
# ============================================================
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
# text.ll 读取缓冲区大小(原 HandlesExprCall 模块级常量)
_TEXT_LL_READ_BUF_SIZE: t.CDefine = 262144
# 闭包名表大小(原 HandlesExprCall 模块级常量)
MAX_CLOSURE_NAMES: t.CDefine = 128
# 函数指针签名表大小(原 HandlesExprCall 模块级常量)
MAX_FUNC_PTR_SIGS: t.CDefine = 64
# ============================================================
# CallGenMixin - 调用分派/类型转换/c.*/stdarg/函数表
# ============================================================
@t.NoVTable
class CallGenMixin:
"""调用分派 Mixin(状态从 HandlesExprCall 全局变量迁入)"""
# --- c.cexport 注册表(原 _g_cexport_sha1_arr/_g_cexport_func_arr/_g_cexport_count) ---
CexportSha1Arr: bytes
CexportFuncArr: bytes
CexportCount: int
# --- LLVMIR 寄存器序号(原 _g_llvmir_reg_seq) ---
LLVMIRRegSeq: int
# --- temp 目录(原 _g_temp_dir/_g_temp_dir_len) ---
TempDir: str
TempDirLen: t.CSizeT
# --- 闭包名表(原 _g_closure_names/_g_closure_count) ---
ClosureNames: t.CChar | t.CPtr
ClosureCount: int
# --- 函数指针签名表(原 _g_funcptr_names/_g_funcptr_rets/_g_funcptr_count) ---
FuncptrNames: t.CChar | t.CPtr
FuncptrRets: t.CUInt64T | t.CPtr
FuncptrCount: int
# --- 全局函数注册表(原 _global_funcs/_global_func_count) ---
GlobalFuncs: HandlesExprCall.FuncEntry | t.CPtr
GlobalFuncCount: int
# --- 全局默认参数表(原 _global_defaults/_global_defaults_count) ---
GlobalDefaults: HandlesExprCall.FuncDefaultsEntry | t.CPtr
GlobalDefaultsCount: int
def InitCallGen(self) -> int:
"""初始化调用 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)"""
if self is None:
return 1
self.CexportSha1Arr = None
self.CexportFuncArr = None
self.CexportCount = 0
self.LLVMIRRegSeq = 0
self.TempDir = None
self.TempDirLen = 0
self.ClosureNames = None
self.ClosureCount = 0
self.FuncptrNames = None
self.FuncptrRets = None
self.FuncptrCount = 0
self.GlobalFuncs = None
self.GlobalFuncCount = 0
self.GlobalDefaults = None
self.GlobalDefaultsCount = 0
return 0
# ============================================================
# P4 簇 1+2 迁移方法(函数体来自 HandlesExprCall.vp:
# 模块 SHA1 查询/CExport 注册表/c.* 系列/内联汇编/LLVMIR)
# 本模块函数调用改 self.,外部模块调用保留模块前缀
# ============================================================
def _lookup_module_sha1(self, mod_name: str) -> str:
"""查找模块名对应的 SHA1,找不到返回 None
委托给 StubMerger.LookupSha1ByModName(精确匹配 + 包名回退)。
"""
return StubMerger.LookupSha1ByModName(mod_name)
def _lookup_module_sha1_suffix(self, mod_suffix: str) -> str:
"""后缀匹配查找模块 SHA1,如 mod_suffix="__types" 匹配 "llvmlite.__types"
用于 from .X import Y 的相对导入:impf.module 是 ".X"(带前导点),
去掉前导点后为 "X",SHA1 映射表中键是 "pkg.X",需要后缀匹配。
委托给 StubMerger.LookupSha1ByModNameSuffix(精确 + 后缀 + 反向后缀)。
"""
return StubMerger.LookupSha1ByModNameSuffix(mod_suffix)
def register_cexport_func(self, sha1: str, func_name: str) -> int:
"""注册 CExport 函数到全局表(sha1+func_name 二元组)"""
if sha1 is None or func_name is None:
return 0
if self.CexportSha1Arr is None:
self.CexportSha1Arr = stdlib.malloc(_CEXPORT_MAX * 17)
self.CexportFuncArr = stdlib.malloc(_CEXPORT_MAX * 64)
if self.CexportSha1Arr is None or self.CexportFuncArr is None:
return 0
string.memset(self.CexportSha1Arr, 0, _CEXPORT_MAX * 17)
string.memset(self.CexportFuncArr, 0, _CEXPORT_MAX * 64)
if self.CexportCount < _CEXPORT_MAX:
idx: t.CSizeT = t.CSizeT(self.CexportCount) * 17
# 槽位定长 17/64 字节,strcpy 无界会越界写相邻槽(stdlib 堆区)
string.strncpy(self.CexportSha1Arr + idx, sha1, 16)
self.CexportSha1Arr[idx + 16] = '\0'
idx2: t.CSizeT = t.CSizeT(self.CexportCount) * 64
string.strncpy(self.CexportFuncArr + idx2, func_name, 63)
self.CexportFuncArr[idx2 + 63] = '\0'
self.CexportCount += 1
return 1
return 0
def is_cexport_func(self, sha1: str, func_name: str) -> int:
"""检查 (sha1, func_name) 是否是 CExport 函数"""
if sha1 is None or func_name is None:
return 0
if self.CexportSha1Arr is None:
return 0
for i in range(self.CexportCount):
idx: t.CSizeT = t.CSizeT(i) * 17
if string.strcmp(self.CexportSha1Arr + idx, sha1) == 0:
idx2: t.CSizeT = t.CSizeT(i) * 64
if string.strcmp(self.CexportFuncArr + idx2, func_name) == 0:
return 1
return 0
def _lookup_mod_sha1(self, pool: memhub.MemBuddy | t.CPtr,
from_imports: str, class_name: str,
allow_star_fallback: int = 1) -> str:
"""从 from_imports 查找类所属模块的 SHA1,返回 None=未找到
allow_star_fallback: 传 0 禁用 star import 回退(用于明确模块名/函数名查找)
"""
mod_name_raw: str = HandlesImports.lookup_from_import(
from_imports, class_name, allow_star_fallback)
if mod_name_raw is None:
return None
return self._lookup_sha1_from_modname_raw(pool, mod_name_raw)
def _lookup_sha1_from_modname_raw(self, pool: memhub.MemBuddy | t.CPtr,
mod_name_raw: str) -> str:
"""从原始模块名查找 SHA1,返回 None=未找到"""
# 手动找到模块名结束位置(空格、null、或 ':' 别名分隔符),复制到新缓冲区
mod_len: t.CSizeT = 0
while mod_name_raw[mod_len] != ' ' and mod_name_raw[mod_len] != '\0' and mod_name_raw[mod_len] != ':':
mod_len += 1
mod_name_buf: str = pool.alloc(mod_len + 1)
if mod_name_buf is None:
return None
for mi in range(mod_len):
mod_name_buf[mi] = mod_name_raw[mi]
mod_name_buf[mod_len] = '\0'
# 去掉相对导入的前导点
base_mod: str = mod_name_buf
while base_mod[0] == '.':
base_mod = base_mod + 1
sha1: str = self._lookup_module_sha1(base_mod)
if sha1 is None:
sha1 = self._lookup_module_sha1_suffix(base_mod)
return sha1
def find_func_in_module(self, mod: llvmlite.LLVMModule | t.CPtr,
name: str) -> llvmlite.Function | t.CPtr:
"""在模块的函数链表中按名称查找函数
查找策略:
1. 精确匹配(如 "strlen" 匹配 @strlen,有 t.CExport 的函数)
2. 后缀匹配(如 "atoi" 匹配 @"83210a72e829a086.atoi",无 t.CExport 的函数)
使用 llvmlite.function_get_name/next 访问器绕过 stub 类型限制
(stub 类型字段不足且字段类型可能错误,直接字段访问会被静默跳过)。
"""
if mod is None or name is None:
return None
name_len: t.CSizeT = string.strlen(name)
cur: llvmlite.Function | t.CPtr = mod.FuncHead
# 第一遍:精确匹配
while cur is not None:
cur_name: t.CChar | t.CPtr = llvmlite.function_get_name(cur)
if cur_name is not None:
if string.strcmp(cur_name, name) == 0:
return cur
cur = llvmlite.function_get_next(cur)
# 第二遍:后缀匹配(.name)
# 不跳过 declare:方法 stub 也是 declare,需要通过后缀匹配找到
# 调用处(translate_call 等)负责判断 IsDeclared 并决定使用裸名还是 sha1 前缀名
#
# 修复:本模块 define 优先于跨模块 stub declare。
# 根因:跨模块同名函数(如 lexer.vp 的 _advance 与 parser.vp 的 _advance)
# 的 stub declare 在 stub 注入时排在 FuncHead 前面,裸名调用 _advance 后缀
# 匹配按链表顺序先命中跨模块 declare → 参数按 Lexer* coerce → Parser* 被
# bitcast 成 Lexer* → lexer 版 _advance 按 Lexer 布局操作 Parser 指针,
# cur 永不推进 → parse 无限循环。本模块同名 define 必须优先。
cur = mod.FuncHead
while cur is not None:
cur_name2: t.CChar | t.CPtr = llvmlite.function_get_name(cur)
if cur_name2 is not None:
cur_len: t.CSizeT = string.strlen(cur_name2)
if cur_len > name_len + 1:
suffix_start: t.CSizeT = cur_len - name_len
if cur_name2[suffix_start - 1] == '.':
match: int = 1
for i in range(name_len):
if cur_name2[suffix_start + i] != name[i]:
match = 0
break
if match == 1:
if cur.IsDeclared == 0:
return cur
cur = llvmlite.function_get_next(cur)
# 本模块无同名 define:回退到 stub declare(跨模块方法/函数调用)
cur = mod.FuncHead
while cur is not None:
cur_name3: t.CChar | t.CPtr = llvmlite.function_get_name(cur)
if cur_name3 is not None:
cur_len3: t.CSizeT = string.strlen(cur_name3)
if cur_len3 > name_len + 1:
suffix_start3: t.CSizeT = cur_len3 - name_len
if cur_name3[suffix_start3 - 1] == '.':
match3: int = 1
for i in range(name_len):
if cur_name3[suffix_start3 + i] != name[i]:
match3 = 0
break
if match3 == 1:
return cur
cur = llvmlite.function_get_next(cur)
return None
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
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 会被截断
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 = win32_apis.__len__()
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: t.CChar | t.CPtr = 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
def translate_c_deref(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""c.Deref(ptr) → load 按 ptr 的 pointee 类型"""
if cl is None:
return None
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 1:
return None
ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), None, 0, trans)
if ptr_val is None:
return None
# 按 pointee 类型读取;非指针参数默认按 i8(保持向后兼容)
if HandlesExpr.is_ptr_type(ptr_val.Ty) != 0:
pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
if pointee is not None:
return llvmlite.build_load(builder, pointee, ptr_val)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
return llvmlite.build_load(builder, i8_ty, ptr_val)
def translate_c_derefas(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""c.DerefAs(ptr, val) → store val to ptr(bitcast 后 store)"""
if cl is None:
return None
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 2:
return None
ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), None, 0, trans)
val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(1), None, 0, trans)
if ptr_val is None or val is None:
return None
# 两端均为指向同一结构体类型的指针时执行结构体拷贝(*ptr = *val),
# 而非存储指针值。这对 REnum 变体构造(c.DerefAs(ptr, LLVMType.Int(32)))至关重要:
# LLVMType.Int(32) 构造返回 alloca 指针(Ptr(LLVMType)),若直接 store 指针值,
# 只写入 8 字节指针(tag 字段仍是 0x0),导致运行时读 tag 错乱。
# 对应 TPC HandlesExprCall.py:3696-3701 的 struct 拷贝逻辑。
if HandlesExpr.is_ptr_type(ptr_val.Ty) != 0 and HandlesExpr.is_ptr_type(val.Ty) != 0:
ptr_pointee: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
val_pointee: llvmlite.LLVMType | t.CPtr = val.Ty.Pointee
if ptr_pointee is not None and val_pointee is not None:
# ptr_pointee 是已注册结构体类型(用 find_struct_by_type 判断)
if HandlesStruct.find_struct_by_type(ptr_pointee) is not None:
if ptr_pointee is val_pointee:
# 同一结构体类型:load 值再 store(结构体拷贝)
loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, val_pointee, val)
if loaded is not None:
# bitcast ptr 到结构体指针再 store
struct_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
pool, ptr_pointee)
casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, ptr_val, struct_ptr_ty)
if casted_ptr is not None:
llvmlite.build_store(builder, loaded, casted_ptr)
return val
# bitcast ptr 到 val.Ty* 再 store
val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, val.Ty)
casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ptr_val, val_ptr_ty)
if casted_ptr is None:
return None
llvmlite.build_store(builder, val, casted_ptr)
return val
def translate_c_set(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""c.Set(a, b) → a = b(赋值语义,a 为左值)"""
if cl is None:
return None
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 2:
return None
a_node: ast.AST | t.CPtr = cargs.get(0)
b_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(1), None, 0, trans)
if b_val is None:
return None
# 形态 1: c.Set(c.Deref(ptr), b) → *ptr = b
if a_node is not None and a_node.kind() == ast.ASTKind.Call:
d_call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(a_node)
if d_call.func is not None and d_call.func.kind() == ast.ASTKind.Attribute:
d_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(d_call.func)
if d_at.attr is not None and string.strcmp(d_at.attr, "Deref") == 0:
d_args: list[ast.AST | t.CPtr] | t.CPtr = d_call.args
if d_args is not None and d_args.__len__() >= 1:
ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, d_args.get(0), None, 0, trans)
if ptr_val is not None:
val_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, b_val.Ty)
casted_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, ptr_val, val_ptr_ty)
if casted_ptr is not None:
llvmlite.build_store(builder, b_val, casted_ptr)
return b_val
# 其他 Call 形态不可作左值
return b_val
# 形态 2: Name 变量赋值
if a_node is not None and a_node.kind() == ast.ASTKind.Name and trans is not None:
nm_set: ast.Name | t.CPtr = (ast.Name | t.CPtr)(a_node)
if nm_set.id is not None:
if HT.is_global_name(trans, nm_set.id) != 0:
mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
trans.SymTab, nm_set.id)
if mod_alloca is not None:
tg_ty: llvmlite.LLVMType | t.CPtr = None
if mod_alloca.Ty is not None:
tg_ty = mod_alloca.Ty.Pointee
sv: llvmlite.Value | t.CPtr = b_val
if tg_ty is not None:
sv = HandlesExpr.coerce_to_type(builder, b_val, tg_ty, a_node)
llvmlite.build_store(builder, sv, mod_alloca)
return b_val
if HT.is_nonlocal_name(trans, nm_set.id) != 0:
nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr(
trans, nm_set.id)
if nl_ptr is not None:
nl_ty: llvmlite.LLVMType | t.CPtr = None
if nl_ptr.Ty is not None:
nl_ty = nl_ptr.Ty.Pointee
sv2: llvmlite.Value | t.CPtr = b_val
if nl_ty is not None:
sv2 = HandlesExpr.coerce_to_type(builder, b_val, nl_ty, a_node)
llvmlite.build_store(builder, sv2, nl_ptr)
return b_val
alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym(
trans.SymTab, pool, builder, nm_set.id, b_val.Ty)
if alloca is not None:
ac_ty: llvmlite.LLVMType | t.CPtr = None
if alloca.Ty is not None:
ac_ty = alloca.Ty.Pointee
sv3: llvmlite.Value | t.CPtr = b_val
if ac_ty is not None:
sv3 = HandlesExpr.coerce_to_type(builder, b_val, ac_ty, a_node)
llvmlite.build_store(builder, sv3, alloca)
return b_val
return b_val
# 形态 3: Attribute 字段赋值
if a_node is not None and a_node.kind() == ast.ASTKind.Attribute:
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
builder, pool, mod, a_node, trans)
if field_ptr is not None:
fd_ty: llvmlite.LLVMType | t.CPtr = None
if field_ptr.Ty is not None:
fd_ty = field_ptr.Ty.Pointee
sv4: llvmlite.Value | t.CPtr = b_val
if fd_ty is not None:
sv4 = HandlesExpr.coerce_to_type(builder, b_val, fd_ty, a_node)
llvmlite.build_store(builder, sv4, field_ptr)
return b_val
return b_val
def translate_c_addr(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""c.Addr(var) → 返回变量的 alloca 指针(不 load)"""
if cl is None:
return None
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 1:
return None
arg0: ast.AST | t.CPtr = cargs.get(0)
if arg0 is None:
return None
# Name 形式: c.Addr(var) → 返回变量的 alloca 指针(不 load)
if arg0.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg0)
if nm.id is None:
return None
if trans is not None:
# self/cls 对象引用:c.Addr(self) 返回对象指针本身(Ptr(Struct)),
# 而非指针变量的地址(Ptr(Ptr(Struct)))。方法与 Attribute 分支
# (c.Addr(self.field) 先 load self)语义一致,供
# return t.CVoid(c.Addr(self), CPtr) 返回 this 使用。
if string.strcmp(nm.id, "self") == 0 or string.strcmp(nm.id, "cls") == 0:
self_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, nm.id)
if self_entry is not None and self_entry.Alloca is not None and self_entry.Alloca.Ty is not None:
match self_entry.Alloca.Ty:
case llvmlite.LLVMType.Ptr(inner1):
match inner1:
case llvmlite.LLVMType.Ptr(inner2):
obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, inner2)
return llvmlite.build_load(builder, obj_ty, self_entry.Alloca)
case _:
pass
case _:
pass
return HandlesVar.lookup_var(trans.SymTab, nm.id)
# Attribute 形式: c.Addr(self.field) → 取字段地址(GEP 到字段,不 load)
# 用于 atom.__atomic_test_and_set(c.Addr(self.lock_val), ...) 等锁操作
if arg0.kind() == ast.ASTKind.Attribute:
if trans is None:
return None
at_addr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(arg0)
if at_addr is None or at_addr.attr is None or at_addr.value is None:
return None
# 解析 self(Name)→ 查找 alloca
if at_addr.value.kind() != ast.ASTKind.Name:
return None
self_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_addr.value)
if self_nm.id is None:
return None
self_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, self_nm.id)
if self_alloca is None or self_alloca.Ty is None:
return None
# 从 self 类型提取结构体类型(Ptr(Struct) 或 Ptr(Ptr(Struct)))
struct_ty: llvmlite.LLVMType | t.CPtr = None
self_is_ptr_ptr: int = 0
match self_alloca.Ty:
case llvmlite.LLVMType.Ptr(inner1):
match inner1:
case llvmlite.LLVMType.Ptr(inner2):
struct_ty = inner2
self_is_ptr_ptr = 1
case _:
struct_ty = inner1
case _:
return None
# 查找字段
fe_addr: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
struct_ty, at_addr.attr)
if fe_addr is None:
return None
# self_alloca 是 Ptr(Ptr(Struct)) 时先 load 成 Ptr(Struct) 对象指针
obj_ptr: llvmlite.Value | t.CPtr = self_alloca
if self_is_ptr_ptr == 1:
self_obj_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
obj_ptr = llvmlite.build_load(builder, self_obj_ty, self_alloca)
if obj_ptr is None:
return None
# GEP 到字段地址
return llvmlite.build_gep_struct(
builder, struct_ty, fe_addr.Ty, obj_ptr, fe_addr.Index)
def translate_c_load(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""c.Load(a, b) → *a = *b(加载 b 的值,存储到 a)"""
if cl is None:
return None
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 2:
return None
dst_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(0), None, 0, trans)
src_ptr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, cargs.get(1), None, 0, trans)
if dst_ptr is None or src_ptr is None:
return None
# 确定 pointee 类型(优先用 src 的 pointee,回退到 dst 的 pointee)
pointee: llvmlite.LLVMType | t.CPtr = None
if src_ptr.Ty is not None:
pointee = src_ptr.Ty.Pointee
if pointee is None and dst_ptr.Ty is not None:
pointee = dst_ptr.Ty.Pointee
if pointee is None:
return None
# bitcast src 到 pointee* 并 load
target_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, pointee)
src_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, src_ptr, target_ptr_ty)
if src_cast is None:
return None
loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, pointee, src_cast)
if loaded is None:
return None
# bitcast dst 到 pointee* 并 store
dst_cast: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, dst_ptr, target_ptr_ty)
if dst_cast is None:
return None
llvmlite.build_store(builder, loaded, dst_cast)
return loaded
def _asm_append_cstr(self, dst: t.CChar | t.CPtr, dst_size: t.CSizeT,
src: t.CChar | t.CPtr):
"""将 C 字符串 src 追加到 dst 末尾"""
if dst is None or src is None:
return
dlen: t.CSizeT = string.strlen(dst)
slen: t.CSizeT = string.strlen(src)
remain: t.CSizeT = dst_size - dlen
if remain <= 0:
return
i: t.CSizeT = 0
while i < slen and i + 1 < remain:
dst[dlen + i] = src[i]
i += 1
dst[dlen + i] = '\0'
def _asm_escape_for_ir(self, pool: memhub.MemBuddy | t.CPtr,
src: t.CChar | t.CPtr) -> t.CChar | t.CPtr:
"""转义汇编文本用于 LLVM IR 字符串字面量"""
if src is None:
return None
slen: t.CSizeT = string.strlen(src)
buf: t.CChar | t.CPtr = pool.alloc(slen * 4 + 8)
if buf is None:
return None
pos: t.CSizeT = 0
for ch in src:
if ch == '\n':
buf[pos] = '\\'
pos += 1
buf[pos] = '0'
pos += 1
buf[pos] = 'A'
pos += 1
elif ch == '"':
buf[pos] = '\\'
pos += 1
buf[pos] = '2'
pos += 1
buf[pos] = '2'
pos += 1
elif ch == '\\':
buf[pos] = '\\'
pos += 1
buf[pos] = '5'
pos += 1
buf[pos] = 'C'
pos += 1
else:
buf[pos] = ch
pos += 1
buf[pos] = '\0'
return buf
def _resolve_register(self, attr_name: str) -> str:
"""将 t.ASM_DESCR.XXX 的属性名映射到约束字符串值"""
if attr_name is None:
return ""
# Clobber 破坏描述符
if string.strcmp(attr_name, "CLOBBER_MEMORY") == 0: return "memory"
if string.strcmp(attr_name, "CLOBBER_CC") == 0: return "cc"
if string.strcmp(attr_name, "CLOBBER_RAX") == 0: return "rax"
if string.strcmp(attr_name, "CLOBBER_RBX") == 0: return "rbx"
if string.strcmp(attr_name, "CLOBBER_RCX") == 0: return "rcx"
if string.strcmp(attr_name, "CLOBBER_RDX") == 0: return "rdx"
if string.strcmp(attr_name, "CLOBBER_RSI") == 0: return "rsi"
if string.strcmp(attr_name, "CLOBBER_RDI") == 0: return "rdi"
if string.strcmp(attr_name, "CLOBBER_RBP") == 0: return "rbp"
if string.strcmp(attr_name, "CLOBBER_RSP") == 0: return "rsp"
if string.strcmp(attr_name, "CLOBBER_R8") == 0: return "r8"
if string.strcmp(attr_name, "CLOBBER_R9") == 0: return "r9"
if string.strcmp(attr_name, "CLOBBER_R10") == 0: return "r10"
if string.strcmp(attr_name, "CLOBBER_R11") == 0: return "r11"
if string.strcmp(attr_name, "CLOBBER_R12") == 0: return "r12"
if string.strcmp(attr_name, "CLOBBER_R13") == 0: return "r13"
if string.strcmp(attr_name, "CLOBBER_R14") == 0: return "r14"
if string.strcmp(attr_name, "CLOBBER_R15") == 0: return "r15"
if string.strcmp(attr_name, "CLOBBER_EAX") == 0: return "eax"
if string.strcmp(attr_name, "CLOBBER_EBX") == 0: return "ebx"
if string.strcmp(attr_name, "CLOBBER_ECX") == 0: return "ecx"
if string.strcmp(attr_name, "CLOBBER_EDX") == 0: return "edx"
if string.strcmp(attr_name, "CLOBBER_ESI") == 0: return "esi"
if string.strcmp(attr_name, "CLOBBER_EDI") == 0: return "edi"
if string.strcmp(attr_name, "CLOBBER_DX") == 0: return "dx"
if string.strcmp(attr_name, "CLOBBER_AX") == 0: return "ax"
if string.strcmp(attr_name, "CLOBBER_CX") == 0: return "cx"
if string.strcmp(attr_name, "CLOBBER_SI") == 0: return "si"
if string.strcmp(attr_name, "CLOBBER_DI") == 0: return "di"
# Output 输出约束
if string.strcmp(attr_name, "OUTPUT_REG") == 0: return "=r"
if string.strcmp(attr_name, "OUTPUT_MEM") == 0: return "=m"
if string.strcmp(attr_name, "OUTPUT_EAX") == 0: return "=a"
if string.strcmp(attr_name, "OUTPUT_EBX") == 0: return "=b"
if string.strcmp(attr_name, "OUTPUT_ECX") == 0: return "=c"
if string.strcmp(attr_name, "OUTPUT_EDX") == 0: return "=d"
if string.strcmp(attr_name, "OUTPUT_ESI") == 0: return "=S"
if string.strcmp(attr_name, "OUTPUT_EDI") == 0: return "=D"
if string.strcmp(attr_name, "OUTPUT_RAX") == 0: return "=a"
if string.strcmp(attr_name, "OUTPUT_RBX") == 0: return "=b"
if string.strcmp(attr_name, "OUTPUT_RCX") == 0: return "=c"
if string.strcmp(attr_name, "OUTPUT_RDX") == 0: return "=d"
if string.strcmp(attr_name, "OUTPUT_RSI") == 0: return "=S"
if string.strcmp(attr_name, "OUTPUT_RDI") == 0: return "=D"
# Input/Register 输入约束
if string.strcmp(attr_name, "REG_ANY") == 0: return "r"
if string.strcmp(attr_name, "REG_EAX") == 0: return "a"
if string.strcmp(attr_name, "REG_EBX") == 0: return "b"
if string.strcmp(attr_name, "REG_ECX") == 0: return "c"
if string.strcmp(attr_name, "REG_EDX") == 0: return "d"
if string.strcmp(attr_name, "REG_ESI") == 0: return "S"
if string.strcmp(attr_name, "REG_EDI") == 0: return "D"
if string.strcmp(attr_name, "REG_RAX") == 0: return "a"
if string.strcmp(attr_name, "REG_RBX") == 0: return "b"
if string.strcmp(attr_name, "REG_RCX") == 0: return "c"
if string.strcmp(attr_name, "REG_RDX") == 0: return "d"
if string.strcmp(attr_name, "REG_RSI") == 0: return "S"
if string.strcmp(attr_name, "REG_RDI") == 0: return "D"
if string.strcmp(attr_name, "INPUT_REG") == 0: return "r"
if string.strcmp(attr_name, "INPUT_MEM") == 0: return "m"
if string.strcmp(attr_name, "INPUT_EAX") == 0: return "a"
if string.strcmp(attr_name, "INPUT_EBX") == 0: return "b"
if string.strcmp(attr_name, "INPUT_ECX") == 0: return "c"
if string.strcmp(attr_name, "INPUT_EDX") == 0: return "d"
if string.strcmp(attr_name, "INPUT_ESI") == 0: return "S"
if string.strcmp(attr_name, "INPUT_EDI") == 0: return "D"
if string.strcmp(attr_name, "INPUT_RAX") == 0: return "a"
if string.strcmp(attr_name, "INPUT_RBX") == 0: return "b"
if string.strcmp(attr_name, "INPUT_RCX") == 0: return "c"
if string.strcmp(attr_name, "INPUT_RDX") == 0: return "d"
if string.strcmp(attr_name, "INPUT_RSI") == 0: return "S"
if string.strcmp(attr_name, "INPUT_RDI") == 0: return "D"
return ""
def _resolve_asm_descr(self, pool: memhub.MemBuddy | t.CPtr,
node: ast.AST | t.CPtr) -> str:
"""递归解析约束表达式,返回约束字符串"""
if node is None:
return ""
k: int = node.kind()
# BinOp with BitOr: 拼接左右
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
if bop.op == ast.OpKind.BitOr:
left_str: str = self._resolve_asm_descr(pool, bop.left)
right_str: str = self._resolve_asm_descr(pool, bop.right)
llen: t.CSizeT = string.strlen(left_str)
rlen: t.CSizeT = string.strlen(right_str)
buf: str = pool.alloc(llen + rlen + 1)
if buf is None:
return ""
string.strcpy(buf, left_str)
for i in range(rlen):
buf[llen + i] = right_str[i]
buf[llen + rlen] = '\0'
return buf
return ""
# Attribute: t.ASM_DESCR.XXX 或 t.XXX
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
# t.ASM_DESCR.XXX
if at.value is not None and at.value.kind() == ast.ASTKind.Attribute:
inner: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(at.value)
if inner.value is not None and inner.value.kind() == ast.ASTKind.Name:
mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(inner.value)
if mod_nm.id is not None and string.strcmp(mod_nm.id, "t") == 0:
if inner.attr is not None and string.strcmp(inner.attr, "ASM_DESCR") == 0:
return self._resolve_register(at.attr)
# t.XXX 简化形式
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
mod_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
if mod_nm2.id is not None and string.strcmp(mod_nm2.id, "t") == 0:
return self._resolve_register(at.attr)
return ""
# Constant: 字符串常量
if k == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
if cn.const_kind == ast.CONST_STR:
return cn.str_val
return ""
return ""
def _asm_get_operand(self, base: HandlesExprCall.AsmOperand | t.CPtr,
idx: int) -> HandlesExprCall.AsmOperand | t.CPtr:
"""获取操作数数组中第 idx 个元素的指针"""
entry_size: t.CSizeT = HandlesExprCall.AsmOperand.__sizeof__()
entry_addr: t.CUInt64T = t.CUInt64T(base) + idx * entry_size
return (HandlesExprCall.AsmOperand | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
def _asm_is_c_call(self, node: ast.Call | t.CPtr) -> str:
"""检查 Call 节点是否是 c.XXX 调用,返回属性名或 None"""
if node is None or node.func is None:
return None
if node.func.kind() != ast.ASTKind.Attribute:
return None
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node.func)
if at.value is None or at.value.kind() != ast.ASTKind.Name:
return None
mod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
if mod_nm.id is None or string.strcmp(mod_nm.id, "c") != 0:
return None
return at.attr
def _asm_add_operand(self, operands: HandlesExprCall.AsmOperand | t.CPtr,
count: int,
val: llvmlite.Value | t.CPtr,
constraint: str,
is_output: int) -> int:
"""添加操作数到数组,返回新计数(失败返回原计数)"""
if count >= ASM_MAX_OPERANDS:
return count
op: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, count)
op.Value = val
op.Constraint = constraint
op.IsOutput = is_output
return count + 1
def translate_c_asm(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""翻译 c.Asm 内联汇编,返回结果 Value(无输出时返回 None)"""
if cl is None:
return None
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 1:
return None
# 分配操作数数组
operand_size: t.CSizeT = HandlesExprCall.AsmOperand.__sizeof__()
operands: HandlesExprCall.AsmOperand | t.CPtr = pool.alloc(operand_size * ASM_MAX_OPERANDS)
if operands is None:
return None
string.memset(operands, 0, operand_size * ASM_MAX_OPERANDS)
# 分配 clobber 名数组
clobbers: str | t.CPtr = pool.alloc(8 * ASM_MAX_OPERANDS)
if clobbers is None:
return None
string.memset(clobbers, 0, 8 * ASM_MAX_OPERANDS)
# 分配 asm 文本缓冲区
asm_text: t.CChar | t.CPtr = pool.alloc(ASM_TEXT_BUF_SIZE)
if asm_text is None:
return None
asm_text[0] = '\0'
operand_count: int = 0
clobber_count: int = 0
fv_count: int = 0
# 分配 fv 索引数组(记录每个 FormattedValue 对应的操作数原始索引)
fv_orig_indices: int | t.CPtr = pool.alloc(4 * ASM_MAX_OPERANDS)
if fv_orig_indices is None:
return None
string.memset(fv_orig_indices, 0, 4 * ASM_MAX_OPERANDS)
# ============================================================
# 1. 解析汇编模板(JoinedStr 或 Constant)— 第一遍:收集操作数
# 不生成 asm 文本(占位符 $N 需在重排后才能确定编号)
# ============================================================
tmpl_node: ast.AST | t.CPtr = cargs.get(0)
if tmpl_node is not None:
tk: int = tmpl_node.kind()
if tk == ast.ASTKind.JoinedStr:
js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node)
jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values
if jvalues is not None:
jvlen: t.CSizeT = jvalues.__len__()
for vi in range(jvlen):
part: ast.AST | t.CPtr = jvalues.get(vi)
if part is None:
continue
pk: int = part.kind()
if pk == ast.ASTKind.FormattedValue:
fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part)
fexpr: ast.AST | t.CPtr = fv.value
if fexpr is None or fexpr.kind() != ast.ASTKind.Call:
continue
fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr)
attr_nm: str = self._asm_is_c_call(fcall)
if attr_nm is None:
continue
is_out: int = 0
if string.strcmp(attr_nm, "AsmOut") == 0:
is_out = 1
elif string.strcmp(attr_nm, "AsmInp") == 0:
is_out = 0
else:
continue
fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args
if fargs is None or fargs.__len__() < 1:
continue
val_node: ast.AST | t.CPtr = fargs.get(0)
cons_str: str = ""
if fargs.__len__() >= 2:
cons_str = self._resolve_asm_descr(pool, fargs.get(1))
if is_out != 0:
# 输出:获取变量 alloca
if val_node is None or val_node.kind() != ast.ASTKind.Name:
continue
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
if nm.id is None:
continue
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id)
if alloca is None:
continue
operand_count = self._asm_add_operand(
operands, operand_count, alloca, cons_str, 1)
else:
# 输入:翻译值
ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, val_node, None, 0, trans)
if ival is None:
continue
operand_count = self._asm_add_operand(
operands, operand_count, ival, cons_str, 0)
# 记录 fv 的原始操作数索引
if fv_count < ASM_MAX_OPERANDS:
fv_orig_indices[fv_count] = operand_count - 1
fv_count += 1
# ============================================================
# 2. 解析关键字参数 out=/inp=/op=/clobber=
# ============================================================
keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords
if keywords is not None:
kwlen: t.CSizeT = keywords.__len__()
for ki in range(kwlen):
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
kwk: int = kw.value.kind()
if string.strcmp(kw.arg, "out") == 0:
# 输出操作数列表
if kwk != ast.ASTKind.List:
continue
out_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value)
out_elts: list[ast.AST | t.CPtr] | t.CPtr = out_lst.elts
if out_elts is None:
continue
oelen: t.CSizeT = out_elts.__len__()
for oi in range(oelen):
oelt: ast.AST | t.CPtr = out_elts.get(oi)
if oelt is None or oelt.kind() != ast.ASTKind.Call:
continue
ocall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(oelt)
oattr: str = self._asm_is_c_call(ocall)
if oattr is None or string.strcmp(oattr, "AsmOut") != 0:
continue
oargs: list[ast.AST | t.CPtr] | t.CPtr = ocall.args
if oargs is None or oargs.__len__() < 1:
continue
oval_node: ast.AST | t.CPtr = oargs.get(0)
ocons: str = ""
if oargs.__len__() >= 2:
ocons = self._resolve_asm_descr(pool, oargs.get(1))
if oval_node is None or oval_node.kind() != ast.ASTKind.Name:
continue
onm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(oval_node)
if onm.id is None:
continue
oalloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, onm.id)
if oalloca is None:
continue
operand_count = self._asm_add_operand(
operands, operand_count, oalloca, ocons, 1)
elif string.strcmp(kw.arg, "inp") == 0 or string.strcmp(kw.arg, "inputs") == 0:
# 输入操作数列表
if kwk != ast.ASTKind.List:
continue
in_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value)
in_elts: list[ast.AST | t.CPtr] | t.CPtr = in_lst.elts
if in_elts is None:
continue
ielen: t.CSizeT = in_elts.__len__()
for ii in range(ielen):
ielt: ast.AST | t.CPtr = in_elts.get(ii)
if ielt is None or ielt.kind() != ast.ASTKind.Call:
continue
icall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(ielt)
iattr: str = self._asm_is_c_call(icall)
if iattr is None or string.strcmp(iattr, "AsmInp") != 0:
continue
iargs: list[ast.AST | t.CPtr] | t.CPtr = icall.args
if iargs is None or iargs.__len__() < 1:
continue
ival_node: ast.AST | t.CPtr = iargs.get(0)
icons: str = ""
if iargs.__len__() >= 2:
icons = self._resolve_asm_descr(pool, iargs.get(1))
ival2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, ival_node, None, 0, trans)
if ival2 is None:
continue
operand_count = self._asm_add_operand(
operands, operand_count, ival2, icons, 0)
elif string.strcmp(kw.arg, "op") == 0 or string.strcmp(kw.arg, "clobber") == 0:
# 破坏列表
if kwk != ast.ASTKind.List:
continue
cl_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(kw.value)
cl_elts: list[ast.AST | t.CPtr] | t.CPtr = cl_lst.elts
if cl_elts is None:
continue
clen: t.CSizeT = cl_elts.__len__()
for ci in range(clen):
celt: ast.AST | t.CPtr = cl_elts.get(ci)
if celt is None:
continue
cstr: str = self._resolve_asm_descr(pool, celt)
if cstr is None or cstr[0] == '\0':
continue
if clobber_count < ASM_MAX_OPERANDS:
cl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8
cl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(cl_addr, t.CPtr))
cl_ptr[0] = cstr
clobber_count += 1
# ============================================================
# 3. 解析第二个位置参数作为破坏列表
# ============================================================
if cargs.__len__() >= 2:
pos_node: ast.AST | t.CPtr = cargs.get(1)
if pos_node is not None and pos_node.kind() == ast.ASTKind.List:
pos_lst: ast.List | t.CPtr = (ast.List | t.CPtr)(pos_node)
pos_elts: list[ast.AST | t.CPtr] | t.CPtr = pos_lst.elts
if pos_elts is not None:
plen: t.CSizeT = pos_elts.__len__()
for pi in range(plen):
pelt: ast.AST | t.CPtr = pos_elts.get(pi)
if pelt is None:
continue
pstr: str = self._resolve_asm_descr(pool, pelt)
if pstr is None or pstr[0] == '\0':
continue
if clobber_count < ASM_MAX_OPERANDS:
pcl_addr: t.CUInt64T = t.CUInt64T(clobbers) + clobber_count * 8
pcl_ptr: str | t.CPtr = (str | t.CPtr)(t.CVoid(pcl_addr, t.CPtr))
pcl_ptr[0] = pstr
clobber_count += 1
# ============================================================
# 4. 统计输出/输入数量,确定返回类型
# ============================================================
output_count: int = 0
input_count: int = 0
first_output_idx: int = -1
for oi2 in range(operand_count):
op2: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi2)
if op2.IsOutput != 0:
if first_output_idx < 0:
first_output_idx = oi2
output_count += 1
else:
input_count += 1
# 确定返回类型
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
if output_count > 0 and first_output_idx >= 0:
out_op: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, first_output_idx)
if out_op.Value is not None and out_op.Value.Ty is not None:
# alloca 的类型是指针,Pointee 是目标类型
if out_op.Value.Ty.Pointee is not None:
ret_ty = out_op.Value.Ty.Pointee
else:
ret_ty = llvmlite.Int32(pool)
# 判断 void — 直接基于 output_count 判断,避免 match 类型匹配问题
is_void: int = 1
if output_count > 0:
is_void = 0
# ============================================================
# 4.5 重排操作数:输出在前,输入在后(LLVM IR 要求)
#
# new_order[new_idx] = orig_idx — 新位置对应原索引
# orig_to_new[orig_idx] = new_idx — 原索引映射到新位置(用于占位符编号)
# ============================================================
new_order: int | t.CPtr = pool.alloc(4 * (operand_count + 1))
orig_to_new: int | t.CPtr = pool.alloc(4 * (operand_count + 1))
if new_order is None or orig_to_new is None:
return None
new_idx: int = 0
# 先放输出
for oi3 in range(operand_count):
op3: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi3)
if op3.IsOutput != 0:
new_order[new_idx] = oi3
new_idx += 1
# 再放输入
for oi4 in range(operand_count):
op4: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, oi4)
if op4.IsOutput == 0:
new_order[new_idx] = oi4
new_idx += 1
# 建立映射 orig -> new
for ni2 in range(operand_count):
orig_to_new[new_order[ni2]] = ni2
# ============================================================
# 4.6 生成汇编文本(第二遍遍历 f-string,用重排后的索引生成占位符)
# 项目约定使用 Intel 语法,通过 IR 的 inteldialect 关键字启用
# ============================================================
if tmpl_node is not None:
tk2: int = tmpl_node.kind()
if tk2 == ast.ASTKind.JoinedStr:
js2: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(tmpl_node)
jvalues2: list[ast.AST | t.CPtr] | t.CPtr = js2.values
if jvalues2 is not None:
jvlen2: t.CSizeT = jvalues2.__len__()
fv_fi: int = 0
for vi2 in range(jvlen2):
part2: ast.AST | t.CPtr = jvalues2.get(vi2)
if part2 is None:
continue
pk2: int = part2.kind()
if pk2 == ast.ASTKind.Constant:
cn3: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part2)
if cn3.const_kind == ast.CONST_STR and cn3.str_val is not None:
self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn3.str_val)
elif pk2 == ast.ASTKind.FormattedValue:
if fv_fi < fv_count:
orig_idx2: int = fv_orig_indices[fv_fi]
new_idx2: int = orig_to_new[orig_idx2]
ph_buf2: t.CChar | t.CPtr = pool.alloc(16)
if ph_buf2 is not None:
viperlib.snprintf(ph_buf2, 16, "$%d", new_idx2)
self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, ph_buf2)
fv_fi += 1
elif tk2 == ast.ASTKind.Constant:
cn4: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(tmpl_node)
if cn4.const_kind == ast.CONST_STR and cn4.str_val is not None:
self._asm_append_cstr(asm_text, ASM_TEXT_BUF_SIZE, cn4.str_val)
# ============================================================
# 5. 构建约束字符串(按重排后的顺序:输出在前,输入在后)
# ============================================================
const_buf: t.CChar | t.CPtr = pool.alloc(ASM_CONST_BUF_SIZE)
if const_buf is None:
return None
const_buf[0] = '\0'
first_const: int = 1
for ci2 in range(operand_count):
orig_i: int = new_order[ci2]
cop: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_i)
cons_val: str = cop.Constraint
if cons_val is None:
cons_val = "r"
if first_const == 0:
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",")
first_const = 0
if cop.IsOutput != 0:
# 输出约束:确保以 = 开头
if cons_val[0] != '=':
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "=")
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val)
else:
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cons_val)
# 追加 clobber 约束 ~{name}
for cidx in range(clobber_count):
cl_addr2: t.CUInt64T = t.CUInt64T(clobbers) + cidx * 8
cname: str = (str | t.CPtr)(t.CVoid(cl_addr2, t.CPtr))[0]
if cname is None or cname[0] == '\0':
continue
if first_const == 0:
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, ",")
first_const = 0
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "~{")
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, cname)
self._asm_append_cstr(const_buf, ASM_CONST_BUF_SIZE, "}")
# ============================================================
# 6. 构建参数列表文本(仅输入操作数)
# ============================================================
args_buf: t.CChar | t.CPtr = pool.alloc(ASM_ARGS_BUF_SIZE)
if args_buf is None:
return None
args_buf[0] = '\0'
first_arg: int = 1
for ai3 in range(operand_count):
orig_i2: int = new_order[ai3]
aop: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, orig_i2)
if aop.IsOutput != 0:
continue
aval: llvmlite.Value | t.CPtr = aop.Value
if aval is None or aval.Ty is None or aval.Name is None:
continue
if first_arg == 0:
self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ", ")
first_arg = 0
# 类型文本
ty_buf: t.CChar | t.CPtr = pool.alloc(64)
if ty_buf is not None:
ty_buf[0] = '\0'
llvmlite.TypePrint(ty_buf, 64, aval.Ty, pool)
self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, ty_buf)
self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, " ")
self._asm_append_cstr(args_buf, ASM_ARGS_BUF_SIZE, aval.Name)
# ============================================================
# 7. 转义汇编文本
# ============================================================
escaped_asm: t.CChar | t.CPtr = self._asm_escape_for_ir(pool, asm_text)
if escaped_asm is None:
return None
# ============================================================
# 8. 生成 IR 行并发射
# ============================================================
line: t.CChar | t.CPtr = pool.alloc(ASM_LINE_BUF_SIZE)
if line is None:
return None
line[0] = '\0'
ssa_name: t.CChar | t.CPtr = None
if is_void == 0:
ssa_name = pool.alloc(16)
if ssa_name is not None:
viperlib.snprintf(ssa_name, 16, "%%%d", builder.Counter)
builder.Counter += 1
# 获取返回类型文本
ret_ty_buf: t.CChar | t.CPtr = pool.alloc(64)
if ret_ty_buf is not None:
ret_ty_buf[0] = '\0'
llvmlite.TypePrint(ret_ty_buf, 64, ret_ty, pool)
if is_void == 1:
viperlib.snprintf(line, ASM_LINE_BUF_SIZE,
"call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)",
ret_ty_buf, escaped_asm, const_buf, args_buf)
else:
viperlib.snprintf(line, ASM_LINE_BUF_SIZE,
"%s = call %s asm sideeffect inteldialect \"%s\", \"%s\"(%s)",
ssa_name, ret_ty_buf, escaped_asm, const_buf, args_buf)
# 发射 IR 到当前块
llvmlite.block_append_text(pool, builder.CurBlock, line)
# ============================================================
# 9. 处理输出:存储结果到输出变量
# ============================================================
if is_void == 0 and first_output_idx >= 0:
result_val: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ret_ty, ssa_name)
out_op2: HandlesExprCall.AsmOperand | t.CPtr = self._asm_get_operand(operands, first_output_idx)
if out_op2.Value is not None:
llvmlite.build_store(builder, result_val, out_op2.Value)
return result_val
return None
def translate_c_llvmir(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""c.LLVMIR 内联 LLVM IR:无返回值,直接嵌入原始 IR 文本
不做指令解析,模板文本(c.LInp/c.LOut 替换后)用 block_append_text
嵌入当前基本块。c.LOut 变量由唯一 SSA 寄存器 %llvmirN 接收结果,
嵌入后自动追加 store 写回变量 alloca。返回 None(无返回值)。
"""
if cl is None or builder is None or pool is None or trans is None:
return None
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or cargs.__len__() < 1:
HandlesType.fatal_error(cl, "c.LLVMIR 缺少模板参数", "TypeError")
# LOut 写回记录(alloca 指针 + 寄存器名),最多 LLVMIR_MAX_OPS 个
out_alloca: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS)
out_regname: t.CSizeT | t.CPtr = pool.alloc(8 * LLVMIR_MAX_OPS)
if out_alloca is None or out_regname is None:
return None
string.memset(out_alloca, 0, 8 * LLVMIR_MAX_OPS)
string.memset(out_regname, 0, 8 * LLVMIR_MAX_OPS)
out_count: int = 0
# 模板文本缓冲区
text: t.CChar | t.CPtr = pool.alloc(LLVMIR_TEMPLATE_BUF)
if text is None:
return None
text[0] = '\0'
# ============================================================
# 1. 解析 IR 模板(JoinedStr 或 Constant)— 替换 LInp/LOut/表达式为值文本
# ============================================================
first_arg: ast.AST | t.CPtr = cargs.get(0)
if first_arg is None:
return None
tk: int = first_arg.kind()
if tk == ast.ASTKind.JoinedStr:
js: ast.JoinedStr | t.CPtr = (ast.JoinedStr | t.CPtr)(first_arg)
jvalues: list[ast.AST | t.CPtr] | t.CPtr = js.values
if jvalues is not None:
jvlen: t.CSizeT = jvalues.__len__()
for vi in range(jvlen):
part: ast.AST | t.CPtr = jvalues.get(vi)
if part is None:
continue
pk: int = part.kind()
if pk == ast.ASTKind.Constant:
# 字符串字面量片段
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(part)
if cn.str_val is not None:
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn.str_val)
elif pk == ast.ASTKind.FormattedValue:
fv: ast.FormattedValue | t.CPtr = (ast.FormattedValue | t.CPtr)(part)
fexpr: ast.AST | t.CPtr = fv.value
if fexpr is None:
continue
# 检测 c.LInp / c.LOut
if fexpr.kind() == ast.ASTKind.Call:
fcall: ast.Call | t.CPtr = (ast.Call | t.CPtr)(fexpr)
attr_nm: str = self._asm_is_c_call(fcall)
if attr_nm is not None:
fargs: list[ast.AST | t.CPtr] | t.CPtr = fcall.args
if fargs is None or fargs.__len__() < 1:
continue
val_node: ast.AST | t.CPtr = fargs.get(0)
if string.strcmp(attr_nm, "LInp") == 0:
# 输入操作数:翻译值,替换为 LLVM 值引用文本(%x 或常量文本)
inp_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, val_node, None, 0, trans)
if inp_val is not None and inp_val.Name is not None:
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, inp_val.Name)
elif string.strcmp(attr_nm, "LOut") == 0:
# 输出操作数:为变量分配唯一 SSA 寄存器 %llvmirN,
# 记录写回(模板嵌入后 store 到变量 alloca)
if val_node is not None and val_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(val_node)
if nm.id is not None:
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, nm.id)
if alloca is None or out_count >= LLVMIR_MAX_OPS:
HandlesType.fatal_error(
fcall,
f"c.LOut 变量 '{nm.id}' 未定义或输出数超过 {LLVMIR_MAX_OPS}",
"TypeError")
self.LLVMIRRegSeq += 1
reg_buf: str = pool.alloc(32)
if reg_buf is not None:
viperlib.snprintf(reg_buf, 32, "%%llvmir_%d", self.LLVMIRRegSeq)
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, reg_buf)
out_alloca[out_count] = t.CSizeT(alloca)
out_regname[out_count] = t.CSizeT(reg_buf)
out_count += 1
continue
# 非 c.LInp/c.LOut 的 f-string 表达式:翻译值并嵌入值文本
ival: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, fexpr, None, 0, trans)
if ival is not None and ival.Name is not None:
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, ival.Name)
elif tk == ast.ASTKind.Constant:
cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg)
if cn2.str_val is not None:
# 裸 strcpy 无界:模板常量串 ≥ LLVMIR_TEMPLATE_BUF 会越界写 pool 块,
# 改用与 JoinedStr 分支一致的有界追加
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn2.str_val)
# ============================================================
# 2. 直接嵌入模板文本(不做指令解析)+ LOut 写回
# ============================================================
llvmlite.block_append_text(pool, builder.CurBlock, text)
# LOut 写回: store <ty> %llvmirN, <ty>* %var
oi: int
for oi in range(out_count):
oa: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(out_alloca[oi], t.CPtr))
rn: str = (t.CChar | t.CPtr)(t.CVoid(out_regname[oi], t.CPtr))
if oa is None or oa.Ty is None or oa.Ty.Pointee is None or rn is None:
continue
reg_val: llvmlite.Value | t.CPtr = llvmlite.new_value(pool)
if reg_val is None:
continue
reg_val.Ty = oa.Ty.Pointee
reg_val.Name = rn
reg_val.IsConst = 0
llvmlite.build_store(builder, reg_val, oa)
return None
# ============================================================
# _apply_struct_defaults — 应用结构体字段的默认值
#
# 在 zeroinitializer 之后、显式参数之前调用
# 遍历所有字段,对有默认值的字段翻译并 store
# 显式参数(位置/关键字)后续会覆盖默认值
# ============================================================
def _apply_struct_defaults(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr,
class_name: str,
tmp: llvmlite.Value | t.CPtr,
trans: HT.Translator | t.CPtr):
"""应用结构体字段的默认值"""
# 用类型指针定位 entry,规避跨模块同名 find_struct 找错
entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
if entry is None:
# fast-fail: 结构体类型未注册,静默 return 会导致字段未初始化
VLogger.error(
f"结构体类型未注册,无法应用默认值: {class_name}",
"HandlesExprCall")
return
for fi in range(entry.FieldCount):
fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
entry, fi)
if fe is None:
# fast-fail: 字段索引越界(entry.FieldCount 与实际不一致)
VLogger.error(
f"字段索引越界,无法获取字段 entry: {class_name}",
"HandlesExprCall")
continue
if fe.DefaultVal is None:
continue # 合理跳过:无默认值的字段
default_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, fe.DefaultVal, None, 0, trans)
if default_val is None:
# fast-fail: 默认值翻译失败(如引用了未定义符号)
VLogger.error(
f"字段默认值翻译失败: {class_name}",
"HandlesExprCall")
continue
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, struct_ty, fe.Ty, tmp, fe.Index)
if field_ptr is None:
# fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配)
VLogger.error(
f"字段 GEP 失败,类型不匹配: {class_name}",
"HandlesExprCall")
continue
default_val = HandlesExpr.coerce_to_type(builder, default_val, fe.Ty, fe.DefaultVal)
llvmlite.build_store(builder, default_val, field_ptr)
# ============================================================
# _translate_struct_ctor — 结构体构造函数 Point(10, 20)
#
# 生成:
# %tmp = alloca {i32, i32}
# store {i32, i32} zeroinitializer, {i32, i32}* %tmp
# %f0 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 0
# store i32 10, i32* %f0
# %f1 = getelementptr {i32, i32}, {i32, i32}* %tmp, i32 0, i32 1
# store i32 20, i32* %f1
# %result = load {i32, i32}, {i32, i32}* %tmp
# ============================================================
def _translate_struct_ctor(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr,
class_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""结构体构造函数:按字段顺序 store 参数值,返回结构体值
OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load
普通结构体:alloca → zero + defaults → store 参数 → load
"""
# 创建临时 alloca
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty)
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
if tmp is None:
return llvmlite.ConstZero(pool, struct_ty)
# 检查是否为 OOP 结构体(用类型指针定位 entry,规避跨模块同名 find_struct 找错)
ctor_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
is_oop: int = 0
if ctor_entry is not None:
is_oop = ctor_entry.IsOOP
# 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods)
# 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入)
# 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠)
if is_oop == 0 and class_name is not None:
init_lookup_name: t.CChar | t.CPtr = pool.alloc(128)
if init_lookup_name is not None:
viperlib.snprintf(init_lookup_name, 128, "%s.__init__", class_name)
# 方案1: 检查当前模块的函数声明
init_found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, init_lookup_name)
if init_found_func is not None:
is_oop = 1
if ctor_entry is not None:
ctor_entry.IsOOP = 1
ctor_entry.HasInit = 1
else:
# 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入)
init_defaults_entry: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(init_lookup_name)
if init_defaults_entry is not None:
is_oop = 1
if ctor_entry is not None:
ctor_entry.IsOOP = 1
ctor_entry.HasInit = 1
if is_oop != 0:
# 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针
storage_ptr: llvmlite.Value | t.CPtr = tmp
# 如果有 __new__,调用 __new__(tmp, args...) 获取实际存储指针
# __new__ 签名与 __init__ 一样(self + args),返回 Ptr(struct_ty)
has_new_flag: int = 0
if ctor_entry is not None:
has_new_flag = ctor_entry.HasNew
# 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法)
if has_new_flag != 0:
new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
if new_arg_vals is not None:
string.memset(new_arg_vals, 0, 8 * 32)
new_arg_count: int = 0
for nai in range(can):
new_arg_node: ast.AST | t.CPtr = cargs.get(nai)
if new_arg_node is None:
continue
new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, new_arg_node, None, 0, trans)
if new_av is not None:
if new_arg_count < 32:
new_arg_vals[new_arg_count] = t.CSizeT(new_av)
new_arg_count += 1
new_ptr: llvmlite.Value | t.CPtr = self._call_method_on_ptr(
pool, builder, mod, class_name,
"__new__", tmp, new_arg_vals, new_arg_count, trans)
if new_ptr is not None:
storage_ptr = new_ptr
# __new__ 只保证返回"实例存储指针",声明类型通常是
# `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。
# 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的
# obj.method(如 parser.add_argument)get_class_name_by_type
# 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。
# bitcast 只改类型层视图,运行时零开销(指针位不变)。
if new_ptr.Ty is not None:
nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty):
nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty)
if nw_bc is not None:
storage_ptr = nw_bc
# OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值
self._call_method_on_ptr(pool, builder, mod, class_name,
"__before_init__", storage_ptr, None, 0, trans)
# 如果有 __init__,调用 __init__(ptr, args...)
# 注意: 仅依据 ctor_entry.HasInit 判断,不强制推断
# (JsonValue 等类有 __new__ 但无 __init__,强制推断会导致 undefined reference)
has_init_flag: int = 0
if ctor_entry is not None:
has_init_flag = ctor_entry.HasInit
if has_init_flag != 0:
# 翻译构造函数参数
arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
if arg_vals is not None:
string.memset(arg_vals, 0, 8 * 32)
real_arg_count: int = 0
for ai in range(can):
arg_node: ast.AST | t.CPtr = cargs.get(ai)
if arg_node is None:
continue
av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg_node, None, 0, trans)
if av is not None:
if real_arg_count < 32:
arg_vals[real_arg_count] = t.CSizeT(av)
real_arg_count += 1
self._call_method_on_ptr(pool, builder, mod, class_name,
"__init__", storage_ptr, arg_vals, real_arg_count, trans)
elif has_new_flag == 0:
# 无 __init__ 且无 __new__:逐字段 store 参数值
# (有 __new__ 时参数已由 __new__ 消费,不应存入字段)
for ai in range(can):
arg: ast.AST | t.CPtr = cargs.get(ai)
if arg is None:
continue
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg, None, 0, trans)
if arg_val is None:
# fast-fail: 参数翻译失败
VLogger.error(
f"构造函数参数翻译失败: {class_name}",
"HandlesExprCall")
continue
fe: HandlesStruct.FieldEntry | t.CPtr = None
if ctor_entry is not None:
# OOP 结构体字段表第 0 个字段是 __vtable__(vtable 指针占位),
# 构造参数按"用户字段顺序"存储:必须跳过 __vtable__ 字段,
# 否则参数会覆盖 vtable 槽(对象头读到垃圾指针,
# isinstance 的 icmp 全部不匹配 + 方法分派错乱)。
# 原实现直接 _get_field_entry(ctor_entry, ai) 取到 __vtable__
# → GEP Index 0 → 覆盖 vtable(Dog("dog") 场景崩溃漂移根因)。
target_idx: int = 0
for fi in range(ctor_entry.FieldCount):
cand_fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
ctor_entry, fi)
if cand_fe is None:
continue
cand_name: str = HandlesStruct.get_field_name_ptr(cand_fe)
if cand_name is not None and string.strcmp(cand_name, "__vtable__") == 0:
continue
if target_idx == ai:
fe = cand_fe
break
target_idx += 1
else:
fe = HandlesStruct.get_field_by_index(class_name, ai)
if fe is None:
# fast-fail: 字段索引越界(用户传了多余参数)
VLogger.error(
f"构造函数参数过多,字段索引越界: {class_name}",
"HandlesExprCall")
continue
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, struct_ty, fe.Ty, storage_ptr, fe.Index)
if field_ptr is None:
# fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配)
VLogger.error(
f"构造函数字段 GEP 失败: {class_name}",
"HandlesExprCall")
continue
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg)
llvmlite.build_store(builder, arg_val, field_ptr)
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
return storage_ptr
# 普通结构体:先 store zeroinitializer 清零(确保未赋值字段为零)
zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty)
llvmlite.build_store(builder, zero, tmp)
# 应用默认值(显式参数会覆盖默认值)
self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans)
# 逐字段 store 参数值(覆盖默认值)
for ai in range(can):
arg: ast.AST | t.CPtr = cargs.get(ai)
if arg is None:
continue
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg, None, 0, trans)
if arg_val is None:
# fast-fail: 参数翻译失败
VLogger.error(
f"构造函数参数翻译失败: {class_name}",
"HandlesExprCall")
continue
# 获取字段信息(用 ctor_entry 规避跨模块同名 find_struct 找错)
fe: HandlesStruct.FieldEntry | t.CPtr = None
if ctor_entry is not None:
fe = HandlesStruct._get_field_entry(ctor_entry, ai)
else:
fe = HandlesStruct.get_field_by_index(class_name, ai)
if fe is None:
# fast-fail: 字段索引越界(用户传了多余参数)
VLogger.error(
f"构造函数参数过多,字段索引越界: {class_name}",
"HandlesExprCall")
continue
# GEP 到字段 ai
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, struct_ty, fe.Ty, tmp, fe.Index)
if field_ptr is None:
# fast-fail: GEP 失败(struct_ty 与 fe.Ty 不匹配)
VLogger.error(
f"构造函数字段 GEP 失败: {class_name}",
"HandlesExprCall")
continue
# 类型转换并 store
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg)
llvmlite.build_store(builder, arg_val, field_ptr)
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
return tmp
# ============================================================
# _translate_renum_construct — REnum 变体构造函数
#
# 语法: ClassName.VariantName(args...)
# 如 LLVMType.Int(1) → 构造 LLVMType 的 Int 变体,__tag=0,_p1=1
#
# 生成 IR:
# %tmp = alloca {i32, i32, ...} ; REnum 类型
# store zeroinitializer, %tmp ; 清零
# %tag_ptr = gep %tmp, 0, 0 ; __tag 字段
# store i32 <tag_value>, %tag_ptr ; 写入 tag
# %p1_ptr = gep %tmp, 0, 1 ; _p1 字段
# store <coerced_arg0>, %p1_ptr ; 写入 payload[0]
# ... (更多 payload 字段)
# return %tmp ; 返回指针
#
# 对应 TPC 的 _HandleREnumConstructLlvm
# ============================================================
def _translate_renum_construct(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str,
variant_name: str,
tag_value: int,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""构造 REnum 变体实例,返回指向 alloca 的指针
class_name: REnum 类名(如 "LLVMType")
variant_name: 变体名(如 "Int")
tag_value: 变体的 tag 值(变体在类中的索引)
cargs: 参数 AST 列表
can: 参数数量
"""
if pool is None or builder is None or class_name is None:
return None
# 查找 REnum 结构体类型(用 find_struct_by_module 规避跨模块同名)
renum_entry: HandlesStruct.StructEntry | t.CPtr = None
if trans is not None:
renum_entry = HandlesStruct.find_struct_by_module(class_name, trans.ModuleSha1)
if renum_entry is None:
renum_entry = HandlesStruct.find_struct(class_name)
if renum_entry is None:
fb_re: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_re is not None:
viperlib.snprintf(fb_re, 1024, "REnum construct: type %s not registered", class_name)
VLogger.error(fb_re, "RENUM")
return None
renum_ty: llvmlite.LLVMType | t.CPtr = renum_entry.Ty
if renum_ty is None:
return None
# alloca REnum 类型
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
HandlesStruct.ensure_struct_def_in_module(pool, mod, renum_ty)
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, renum_ty)
if tmp is None:
return llvmlite.ConstZero(pool, renum_ty)
# 清零(确保未赋值的 payload 位置为零)
zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, renum_ty)
llvmlite.build_store(builder, zero, tmp)
# 写入 __tag 字段(索引 0)
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
tag_name_buf: t.CChar | t.CPtr = pool.alloc(32)
if tag_name_buf is not None:
viperlib.snprintf(tag_name_buf, 32, "%d", tag_value)
tag_const: llvmlite.Value | t.CPtr = llvmlite.ConstInt(
pool, i32_ty, tag_value,
tag_name_buf if tag_name_buf is not None else "0")
tag_field: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(renum_entry, 0)
tag_field_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if tag_field is not None and tag_field.Ty is not None:
tag_field_ty = tag_field.Ty
tag_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, renum_ty, tag_field_ty, tmp, 0)
if tag_ptr is not None:
llvmlite.build_store(builder, tag_const, tag_ptr)
# 写入 payload 字段(索引 1, 2, ... 对应 _p1, _p2, ...)
# 参数按位置顺序填充 payload,跳过 __tag(索引 0)
for ai in range(can):
arg: ast.AST | t.CPtr = cargs.get(ai)
if arg is None:
continue
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg, None, 0, trans)
if arg_val is None:
continue
# payload 字段索引 = ai + 1(跳过 __tag)
payload_idx: int = ai + 1
if payload_idx >= renum_entry.FieldCount:
break
pfe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
renum_entry, payload_idx)
if pfe is None:
continue
payload_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, renum_ty, pfe.Ty, tmp, payload_idx)
if payload_ptr is None:
continue
# 类型转换并 store(payload 位置可能是 i32 或 i64,按字段类型 coerce)
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, pfe.Ty, arg)
llvmlite.build_store(builder, arg_val, payload_ptr)
# 返回指针(与 _translate_struct_ctor 一致,赋值时由 coerce_to_type 决定是否 load)
return tmp
# ============================================================
# _do_virtual_call — 通过虚表间接调用虚方法
#
# IR 模式:
# %1 = getelementptr StructTy, StructTy* %self, i32 0, i32 0 ; i8**
# %2 = load i8*, i8** %1 ; i8* (vtable ptr)
# %3 = bitcast i8* %2 to {i8*, ...}* ; vtable typed ptr
# %4 = getelementptr {i8*, ...}, {i8*, ...}* %3, i32 0, i32 N ; i8**
# %5 = load i8*, i8** %4 ; i8* (func ptr)
# %6 = bitcast i8* %5 to RetTy(Params)* ; func typed ptr
# call RetTy %6(Params %self, ...)
#
# 参数:
# args_head — 已构建好的参数链表头(self_ptr 为首节点)
# args_count — 参数总数(含 self)
# found_func — 方法对应的 Function 对象(用于推断函数签名)
# ret_ty — 返回类型
# ============================================================
def _do_virtual_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str,
method_name: str,
self_ptr: llvmlite.Value | t.CPtr,
args_head: llvmlite.Value | t.CPtr,
args_count: int,
found_func: llvmlite.Function | t.CPtr,
ret_ty: llvmlite.LLVMType | t.CPtr,
vtable_base: llvmlite.Value | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""通过虚表间接调用虚方法,返回 call 结果(void 方法返回 None)
vtable_base: 对象头指针(vtable 所在位置,即未调整的 obj_ptr)。
多继承 this 调整后 self_ptr 可能前移(如 obj+4 指向父类字段区),
从调整后位置读 vtable 会读到字段值 → 垃圾指针崩溃。默认 None 时
vtable_base = self_ptr(未调整场景,读对象头)。
"""
if pool is None or builder is None or class_name is None or method_name is None:
return None
if self_ptr is None or args_head is None:
return None
if vtable_base is None:
vtable_base = self_ptr
# 1. 获取结构体类型(用 find_struct_by_type 规避跨模块同名 find_struct 找错)
vc_entry: HandlesStruct.StructEntry | t.CPtr = None
struct_ty: llvmlite.LLVMType | t.CPtr = None
if self_ptr.Ty is not None:
vc_entry = HandlesStruct.get_struct_type_from_value(self_ptr)
if vc_entry is not None:
# vc_entry 是 struct_ty(LLVMType),需要找 StructEntry
vc_entry = HandlesStruct.find_struct_by_type(vc_entry)
if vc_entry is not None:
struct_ty = vc_entry.Ty
if struct_ty is None:
struct_ty = HandlesStruct.get_struct_type(class_name)
if struct_ty is None:
return None
# 2. 获取方法在虚表中的索引(用 entry 直接查找)
method_index: int = -1
if vc_entry is not None and vc_entry.VTableMethods is not None:
methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(vc_entry.VTableMethods, t.CPtr))
for mi in range(vc_entry.VTableMethodCount):
mname_addr: t.CSizeT = methods_arr[mi]
if mname_addr == 0:
continue
mname: str = (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr))
if mname is not None and string.strcmp(mname, method_name) == 0:
method_index = mi
break
else:
method_index = HandlesStruct.get_vtable_method_index(class_name, method_name)
if method_index < 0:
return None
# 3. 基础类型
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
# 4. bitcast 到 i8** 访问 __vtable__ 字段(索引 0)
# vtable 指针总是在对象第一个字段,无需 GEP,直接 bitcast 到 i8** 即可。
# 这样即使 struct_ty 是 opaque(跨模块未加载完整定义)也能正常工作。
# 注意用 vtable_base(对象头)而非 self_ptr:多继承 this 调整后
# self_ptr 已前移,其头部不是 vtable 而是父类字段值。
vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, vtable_base, i8_ptr_ptr_ty)
if vtable_slot is None:
return None
# 5. load vtable 指针 (i8*)
vtable_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot)
if vtable_ptr is None:
return None
# 6. 构造 vtable 类型 {i8*, i8*, ...}
method_count: int = 0
if vc_entry is not None:
method_count = vc_entry.VTableMethodCount
else:
method_count = HandlesStruct.get_vtable_method_count(class_name)
if method_count <= 0:
return None
vt_first: llvmlite.ParamNode | t.CPtr = None
vt_prev: llvmlite.ParamNode | t.CPtr = None
for vi in range(method_count):
pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty)
if pn is None:
continue
if vt_first is None:
vt_first = pn
if vt_prev is not None:
llvmlite.paramnode_set_next(vt_prev, pn)
vt_prev = pn
vtable_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Struct(pool, vt_first, method_count, None)
if vtable_ty is None:
return None
vtable_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, vtable_ty)
# 7. bitcast i8* 到 vtable 类型指针
vtable_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, vtable_ptr, vtable_ptr_ty)
if vtable_typed is None:
return None
# 8. GEP 到方法槽位
func_slot: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, vtable_ty, i8_ptr_ty, vtable_typed, method_index)
if func_slot is None:
return None
# 9. load 函数指针 (i8*)
func_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, func_slot)
if func_i8 is None:
return None
# 10. 从 args_head 构造函数类型 RetTy(Param1, Param2, ...)
# 直接遍历 Value 链表提取参数类型,避免跨模块访问 found_func(stub 字段偏移问题)
fp_first: llvmlite.ParamNode | t.CPtr = None
fp_prev: llvmlite.ParamNode | t.CPtr = None
fp_count: int = 0
cur_val: llvmlite.Value | t.CPtr = args_head
for vi in range(args_count):
if cur_val is None:
break
cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_val)
fpn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty)
if fpn is not None:
if fp_first is None:
fp_first = fpn
if fp_prev is not None:
llvmlite.paramnode_set_next(fp_prev, fpn)
fp_prev = fpn
cur_val = llvmlite.value_get_next(cur_val)
fp_count += 1
func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, fp_count)
if func_ty is None:
return None
func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty)
# 11. bitcast i8* 到函数指针类型
func_ptr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, func_i8, func_ptr_ty)
if func_ptr is None:
return None
# 12. 间接调用
return llvmlite.build_call_indirect(builder, func_ptr, args_head, args_count, ret_ty)
# ============================================================
# _call_method_on_ptr — 在结构体指针上调用方法
#
# 辅助函数:构造 ClassName.method_name 调用,self 指针为首个参数
# 如果该方法在虚表中,则走虚方法分发路径(间接调用)
# ============================================================
def _call_method_on_ptr(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str,
method_name: str,
self_ptr: llvmlite.Value | t.CPtr,
extra_args: t.CSizeT | t.CPtr,
extra_count: int,
trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""在结构体指针上调用方法,返回 call 结果(void 方法返回 None)
node: 触发本次调用的 AST 节点(如 Subscript 下标节点),用于 fatal_error
准确报告出错行号(传 None 时行号显示 0,不利于定位)。"""
if pool is None or builder is None or class_name is None or method_name is None:
return None
if self_ptr is None:
return None
# 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错)
# 用于 SHA1 查找和虚表分派
cmop_entry: HandlesStruct.StructEntry | t.CPtr = None
cmop_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(self_ptr)
if cmop_struct_ty is not None:
cmop_entry = HandlesStruct.find_struct_by_type(cmop_struct_ty)
if cmop_entry is None:
cmop_entry = HandlesStruct.find_struct(class_name)
# fallback: 若 cmop_struct_ty 为 None 但 entry 存在,从 entry 获取类型
# 用于跨模块调用时 self_ptr 类型信息丢失的情况
if cmop_struct_ty is None and cmop_entry is not None:
cmop_struct_ty = cmop_entry.Ty
# 构造方法查找名: ClassName.method_name
lookup_name: t.CChar | t.CPtr = pool.alloc(128)
if lookup_name is None:
return None
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
# 查找函数(支持 SHA1 后缀匹配)
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name)
# 确定调用名
call_name: str = lookup_name
if found_func is not None:
found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
if found_name is not None:
call_name = found_name
else:
# found_func 为 None(stub 未注入):用类所属模块的 SHA1 构造调用名
# 优先从 entry 获取 SHA1(规避跨模块同名 find_struct 找错)
cls_sha1: str = None
if cmop_entry is not None:
cls_sha1 = cmop_entry.ModuleSha1
else:
cls_sha1 = HandlesStruct.get_struct_sha1(class_name)
if cls_sha1 is None and trans is not None:
# fallback: 从 from_imports 查找类所属模块的 SHA1(含截断处理)
cls_sha1 = self._lookup_mod_sha1(pool, trans._from_imports, class_name)
if cls_sha1 is None:
err_msg: t.CChar | t.CPtr = pool.alloc(256)
if err_msg is not None:
viperlib.snprintf(err_msg, 256, "类 '%s' 方法 '%s' 找不到模块 SHA1", class_name, method_name)
HandlesType.fatal_error(node, err_msg)
HandlesType.fatal_error(node, "找不到模块 SHA1")
mangled_len2: t.CSizeT = string.strlen(cls_sha1) + string.strlen(lookup_name) + 2
mangled2: str = pool.alloc(mangled_len2)
if mangled2 is not None:
viperlib.snprintf(mangled2, mangled_len2, "%s.%s", cls_sha1, lookup_name)
call_name = mangled2
# 确定返回类型(__before_init__ 和 __init__ 返回 void)
void_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
call_ret_ty: llvmlite.LLVMType | t.CPtr = void_ty
if found_func is not None:
frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
if frt is not None:
call_ret_ty = frt
elif string.strcmp(method_name, "__getitem__") == 0 or string.strcmp(method_name, "__new__") == 0:
# fail-fast:__getitem__/__new__ 必返回指针,返回类型缺失意味着
# stub declare 损坏,静默推断会截断指针(32 位)崩溃,立即终止。
err_cm1: t.CChar | t.CPtr = pool.alloc(256)
if err_cm1 is not None:
viperlib.snprintf(err_cm1, 256,
"方法 '%s' 返回类型无法确定(stub declare 返回类型缺失)", method_name)
HandlesType.fatal_error(node, err_cm1)
HandlesType.fatal_error(node, "方法返回类型无法确定")
else:
# found_func 为 None(跨模块调用 stub 未注入):无法从 declare 获取返回类型。
# __new__ 返回 Ptr(struct_ty)(构造函数返回自身指针,可推断)。
# __getitem__ 返回类型无法从 self 推断(可返回 i8* 如 HashTable.__getitem__
# -> t.CPtr,或 Ptr(JsonValue) 如 JsonValue.__getitem__)——推断 Ptr(cmop_struct_ty)
# 会与 define 返回类型不匹配,调用侧按错误类型读取返回值导致指针截断崩溃。
# fail-fast:__getitem__ 无 stub declare 立即报错,暴露依赖模块 vpi 缺失或
# 拓扑顺序错误(依赖模块未先翻译生成 vpi/text.ll)。
if string.strcmp(method_name, "__new__") == 0:
if cmop_struct_ty is not None:
call_ret_ty = llvmlite.Ptr(pool, cmop_struct_ty)
else:
err_cm2: t.CChar | t.CPtr = pool.alloc(256)
if err_cm2 is not None:
viperlib.snprintf(err_cm2, 256,
"方法 '%s' 的 self 结构体类型未知(字段类型退化,依赖模块未预注册?)", method_name)
HandlesType.fatal_error(node, err_cm2)
HandlesType.fatal_error(node, "self 结构体类型未知")
elif string.strcmp(method_name, "__getitem__") == 0:
err_cm3: t.CChar | t.CPtr = pool.alloc(256)
if err_cm3 is not None:
viperlib.snprintf(err_cm3, 256,
"方法 '%s.__getitem__' 的 stub declare 未注入(依赖模块 vpi 缺失或拓扑顺序错误),无法确定返回类型",
class_name)
HandlesType.fatal_error(node, err_cm3)
HandlesType.fatal_error(node, "__getitem__ stub declare 未注入")
# 构建参数链表: self_ptr → extra_args...
llvmlite.value_set_next(self_ptr, None)
head: llvmlite.Value | t.CPtr = self_ptr
tail: llvmlite.Value | t.CPtr = self_ptr
if extra_args is not None and extra_count > 0:
for ei in range(extra_count):
arg_addr: t.CSizeT = extra_args[ei]
if arg_addr == 0:
continue
av: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(t.CVoid(arg_addr, t.CPtr))
if av is not None:
llvmlite.value_set_next(av, None)
llvmlite.value_set_next(tail, av)
tail = av
total_count: int = 1 + extra_count
# 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数
# 优先用函数定义的默认值,无默认值时用零值兜底
# 查找函数的 defaults 信息
mdf_defaults: t.CVoid | t.CPtr = None
mdf_default_count: int = 0
mdf_param_count: int = 0
if trans is not None and trans._funcs is not None:
mdf_entry: FuncEntry | t.CPtr = HandlesExprCall.find_func_entry_in_table(
trans._funcs, trans._func_count, lookup_name)
if mdf_entry is not None:
mdf_defaults = mdf_entry.Defaults
mdf_default_count = mdf_entry.DefaultCount
mdf_param_count = mdf_entry.ParamCount
if mdf_defaults is None:
mdf_gd: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(lookup_name)
if mdf_gd is not None:
mdf_defaults = mdf_gd.Defaults
mdf_default_count = mdf_gd.DefaultCount
mdf_param_count = mdf_gd.ParamCount
# 计算需要填充的参数(不含 self)
# extra_count = 已提供的非 self 参数数量
# mdf_param_count = 函数定义的非 self 参数数量
if mdf_param_count > extra_count:
mdf_offset: int = mdf_param_count - mdf_default_count
mdf_pi: int = extra_count
while mdf_pi < mdf_param_count:
# 优先用默认值
if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset:
mdf_di: int = mdf_pi - mdf_offset
if mdf_di < mdf_default_count:
# 用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收,
# 直接回退读 AST 会 use-after-free——快照失败时 fail-fast 暴露,绝不读悬空 AST)
mdf_val: llvmlite.Value | t.CPtr = None
if mdf_gd is not None:
mdf_val = HandlesExprCall._build_const_from_snapshot(
pool, mod, mdf_gd, mdf_di, trans, builder)
if mdf_val is None:
HandlesType.fatal_error(
cl,
f"跨模块默认参数无法重建(快照缺失,默认值需为简单常量): {lookup_name}",
"TypeError")
continue
llvmlite.value_set_next(mdf_val, None)
llvmlite.value_set_next(tail, mdf_val)
tail = mdf_val
total_count += 1
mdf_pi += 1
continue
# 无默认值时用零值兜底(需要 found_func 获取参数类型)
if found_func is not None:
param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
skip_z: int = 0
while skip_z <= mdf_pi and param_node_z is not None:
param_node_z = llvmlite.param_get_next(param_node_z)
skip_z += 1
if param_node_z is not None:
zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z)
zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty)
if zero_val is not None:
llvmlite.value_set_next(zero_val, None)
llvmlite.value_set_next(tail, zero_val)
tail = zero_val
total_count += 1
mdf_pi += 1
elif found_func is not None:
# 无默认参数信息但有 found_func:用零值填充(保留原有逻辑)
param_node: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
skip_idx: int = 0
while skip_idx < total_count and param_node is not None:
param_node = llvmlite.param_get_next(param_node)
skip_idx += 1
while param_node is not None:
missing_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node)
zero_val2: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, missing_ty)
if zero_val2 is not None:
llvmlite.value_set_next(zero_val2, None)
llvmlite.value_set_next(tail, zero_val2)
tail = zero_val2
total_count += 1
param_node = llvmlite.param_get_next(param_node)
# 参数类型强制转换:按 found_func 的形参类型 coerce 每个实参(跳过 self/cls 参数 0)
# 修复: 构造器调用 __init__(ptr, base, 4096) 时 size 形参是 i64 (t.CSizeT),
# 但 4096 字面量按 i32 传递,未提升导致运行时 size 高 32 位垃圾,
# 破坏伙伴分配器的池大小元数据(如 total=2048)引发 calloc 失败/OOM。
if found_func is not None and head is not None:
pc_param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
# 跳过 self 参数(索引 0)
if pc_param is not None:
pc_param = llvmlite.param_get_next(pc_param)
pc_node: llvmlite.Value | t.CPtr = head.Next
new_tail: llvmlite.Value | t.CPtr = head
if head is not None:
head.Next = None
while pc_node is not None:
pc_next_save: llvmlite.Value | t.CPtr = pc_node.Next
coerced_pc: llvmlite.Value | t.CPtr = pc_node
if pc_param is not None:
pty_pc: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pc_param)
if pty_pc is not None:
c_pc: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, pc_node, pty_pc, None)
if c_pc is not None:
coerced_pc = c_pc
pc_param = llvmlite.param_get_next(pc_param)
coerced_pc.Next = None
new_tail.Next = coerced_pc
new_tail = coerced_pc
pc_node = pc_next_save
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用
# 复用前面已获取的 cmop_entry(find_struct_by_type 规避跨模块同名找错)
if found_func is not None:
cmop_has_vt: int = 0
cmop_method_idx: int = -1
if cmop_entry is not None:
cmop_has_vt = cmop_entry.HasVTable
if cmop_has_vt == 1 and cmop_entry.VTableMethods is not None:
cmop_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(cmop_entry.VTableMethods, t.CPtr))
for cmop_mi in range(cmop_entry.VTableMethodCount):
cmop_mname_addr: t.CSizeT = cmop_methods_arr[cmop_mi]
if cmop_mname_addr == 0:
continue
cmop_mname: str = (str | t.CPtr)(t.CVoid(cmop_mname_addr, t.CPtr))
if cmop_mname is not None and string.strcmp(cmop_mname, method_name) == 0:
cmop_method_idx = cmop_mi
break
if cmop_has_vt == 1 and cmop_method_idx >= 0:
return self._do_virtual_call(pool, builder, mod, class_name, method_name,
self_ptr, head, total_count, found_func, call_ret_ty)
# 跨模块调用(found_func 为 None):创建 declare 声明,避免 llc 报 undefined value
if found_func is None:
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count)
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, 0)
# ============================================================
# _ensure_method_declare - 为跨模块方法调用创建 declare 声明
#
# 当 found_func 为 None(stub 未注入或跨模块调用)时,
# 在当前模块中创建函数声明,避免 llc 报 undefined value。
# ============================================================
def _ensure_method_declare(self, pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
call_name: str,
ret_ty: llvmlite.LLVMType | t.CPtr,
param_head: llvmlite.ParamNode | t.CPtr,
param_count: int):
"""为跨模块方法调用创建 declare 声明
若模块中已存在同名 declare 且参数数量较少(例如 File.__init__ 的
stub 仅 3 个参数,而实际调用传入 4 个),则向现有 declare 追加缺失
参数,避免 llc 报 `argument invalid for parameter type` 之类的错误。
已存在的 define 不修改(其参数由定义决定)。
"""
if pool is None or mod is None or call_name is None:
return
# 检查模块中是否已有同名函数(declare 或 define)
existing: llvmlite.Function | t.CPtr = mod.FuncHead
while existing is not None:
if existing.Name is not None:
if string.strcmp(existing.Name, call_name) == 0:
# 已存在:仅当是 declare 且参数数量不足时追加缺失参数
if existing.IsDeclared == 1:
# 变长函数(*args,IsVarArg=1)不追加参数:多余实参由
# 变参机制(...)承接,追加有类型参数会导致调用侧把变参
# 强转为追加的类型(如 i8 → i64),%d/%x 等格式读错。
if existing.IsVarArg == 1:
return
# 遍历现有参数链表计数(避免依赖 GSList.Count 字段的类型推断)
cur_count: int = 0
cur_p: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(existing)
while cur_p is not None:
cur_count += 1
cur_p = cur_p.Next
# 只追加缺失的参数(cur_count < param_count 时)
if cur_count < param_count:
# 定位到 param_head 的第 cur_count 个节点开始追加
pnode2: llvmlite.ParamNode | t.CPtr = param_head
pi2: int = 0
# 跳过已有的 cur_count 个参数
while pnode2 is not None and pi2 < cur_count:
pnode2 = pnode2.Next
pi2 += 1
# 追加剩余参数
while pnode2 is not None and pi2 < param_count:
if pnode2.Ty is not None:
param2: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode2.Ty, None)
if param2 is not None:
llvmlite.function_add_param(existing, param2)
pnode2 = pnode2.Next
pi2 += 1
return
existing = existing.Next
# 创建函数声明
func: llvmlite.Function | t.CPtr = llvmlite.new_function(pool, call_name, ret_ty)
if func is None:
return
func.IsDeclared = 1
# 添加参数(declare 中参数名无意义,设为 None 只输出类型)
pnode: llvmlite.ParamNode | t.CPtr = param_head
pi: int = 0
while pnode is not None and pi < param_count:
if pnode.Ty is not None:
param: llvmlite.Param | t.CPtr = llvmlite.new_param(pool, pnode.Ty, None)
if param is not None:
llvmlite.function_add_param(func, param)
pnode = pnode.Next
pi += 1
llvmlite.module_add_function(mod, func)
# ============================================================
# _lookup_method_ret_ty_via_vpi - 从 vpi stub 返回注解缓存精确获取方法返回类型
#
# 方法定义处(.vpi stub)的返回注解(如 json.JsonValue._pool_alloc →
# "t.CChar | t.CPtr")在 stub 注入时由 VpiReader 缓存(_cache_vpi_return_annots_text)。
# 此函数按 模块SHA1 + 类名 + 方法名 查缓存并纯字符串解析为 LLVMType。
# 无需硬编码白名单——返回类型始终来自方法定义处。
# ============================================================
def _lookup_method_ret_ty_via_vpi(self, pool: memhub.MemBuddy | t.CPtr,
cls_sha1: str,
cls_name: str,
method_name: str) -> llvmlite.LLVMType | t.CPtr:
"""从 vpi stub 返回注解缓存获取方法返回类型,未命中返回 None"""
if VpiReader.VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-CALL] lookup sha1=%s cls=%s m=%s tdlen=%d\n",
cls_sha1, cls_name, method_name, self.TempDirLen)
if pool is None or cls_sha1 is None or method_name is None:
return None
# 函数内懒 import:VpiReader imports HandlesExprCall,顶层 import 会成环
import lib.StubGen.VpiReader as VpiReader
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, llvmlite.Int8(pool))
# 按需加载:缓存未命中时直接读 {temp_dir}/{sha1[0:2]}/{sha1}.vpi
# 覆盖"模块自身翻译时 stub 尚未注入"(同模块方法调用,定义在后)的场景
if self.TempDir is not None and self.TempDirLen > 0:
VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, self.TempDir)
annot: str = VpiReader._lookup_vpi_ret_annot(cls_sha1, cls_name, method_name)
if annot is None:
if VpiReader.VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-CALL] annot=NONE\n")
return None
if VpiReader.VPI_DEBUG_ENABLE != 0:
stdio.printf("[VPI-CALL] annot=%s\n", annot)
return VpiReader._resolve_vpi_ret_annot_str(pool, annot, i32_ty, i8_ptr_ty)
# ============================================================
# _special_method_ret_ty - 编译器内置特殊方法的固定返回类型
#
# __before_init__ / __init__:编译器生成/约定返回 void
# __new__:返回 Ptr(StructTy)(存储空间指针)
#
# 这些方法不存在于源码(vpi stub 无条目),跨模块调用时
# found_func/text.ll/vpi 缓存必然未命中,但返回类型是编译器
# 确定性语义(与 HandlesClassDef._translate_method 3543-3548 一致),
# 在此直接固定,不触发 fail-fast 误报。非特殊方法返回 None。
# ============================================================
def _special_method_ret_ty(self, pool: memhub.MemBuddy | t.CPtr,
class_name: str,
method_name: str) -> llvmlite.LLVMType | t.CPtr:
"""编译器内置特殊方法的固定返回类型;非特殊返回 None"""
if pool is None or method_name is None:
return None
if string.strcmp(method_name, "__before_init__") == 0 or \
string.strcmp(method_name, "__init__") == 0:
return llvmlite.Void(pool)
if string.strcmp(method_name, "__new__") == 0:
if class_name is not None:
sp_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name)
if sp_struct_ty is not None:
return llvmlite.Ptr(pool, sp_struct_ty)
return None
return None
# ============================================================
# _fail_method_ret_ty - 方法返回类型无法精确获取时 fail-fast
#
# 返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。
# 全部未命中时立即 ERROR + 错误堆栈终止,绝不按名推断白名单/静默默认 i32。
#
# node: 调用点 AST 节点(可选,用于 ERROR 堆栈定位)
# ============================================================
def _fail_method_ret_ty(self, method_name: str,
node: ast.AST | t.CPtr = None) -> llvmlite.LLVMType | t.CPtr:
"""方法返回类型无法精确获取时 fail-fast(ERROR + 错误堆栈)
返回类型来源(按序):当前模块函数 → text.ll define → vpi stub 返回注解缓存。
全部未命中说明方法定义缺失或 stub 损坏,立即终止暴露,绝不静默默认 i32。
"""
VLogger.error(
f"方法返回类型无法精确获取(函数/text.ll/vpi stub 均未命中): {method_name}",
"HandlesExprCall")
HandlesType.fatal_error(
node,
f"方法返回类型无法精确获取,默认 i32 会截断指针/i64: {method_name}",
"TypeError")
return None
# ============================================================
# SetTempDir - 设置 temp 目录路径
#
# 在 Phase2.py 的 Phase A 翻译前调用,使 CallGenMixin
# 能够读取依赖模块的 text.ll 文件。
# ============================================================
def SetTempDir(self, temp_dir: str):
"""设置 temp 目录路径(供跨模块方法返回类型查找使用)"""
self.TempDir = temp_dir
if temp_dir is not None:
self.TempDirLen = string.strlen(temp_dir)
else:
self.TempDirLen = 0
# ============================================================
# _ParseLLVMRetTyStr - 将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType
#
# 从 define 行中提取的返回类型字符串(define 与 @ 之间的内容),
# 转换为 llvmlite.LLVMType 对象。
#
# 支持的类型:
# void → Void
# i8/i16/i32/i64 → Int8/Int16/Int32/Int64
# double → Double, float → Float
# 任何含 * 的类型 → Ptr(Int8)(通用指针,保留 64 位地址)
#
# Args:
# pool: 内存池
# buf: 包含类型字符串的缓冲区
# start: 类型字符串起始位置
# end: 类型字符串结束位置(不含)
#
# Returns:
# LLVM 类型对象,或 None(无法解析)
# ============================================================
def _ParseLLVMRetTyStr(self, pool: memhub.MemBuddy | t.CPtr,
buf: bytes,
start: t.CSizeT,
end: t.CSizeT) -> llvmlite.LLVMType | t.CPtr:
"""将 LLVM IR 返回类型字符串转换为 llvmlite.LLVMType"""
if pool is None or buf is None or start >= end:
return None
# 去除前导空白
s: t.CSizeT = start
while s < end:
c: int = buf[s]
if c != ' ' and c != '\t':
break
s += 1
# 去除尾部空白
e: t.CSizeT = end
while e > s:
c2: int = buf[e - 1]
if c2 != ' ' and c2 != '\t':
break
e -= 1
ty_len: t.CSizeT = e - s
if ty_len == 0:
return None
# 检查是否含 * (指针类型) → 返回 i8* (通用指针)
# 包括 i8*, i32*, %"name"*, { i32, i8 }* 等
ci: t.CSizeT = s
while ci < e:
if buf[ci] == '*':
return llvmlite.Ptr(pool, llvmlite.Int8(pool))
ci += 1
# void
if ty_len == 4 and string.strncmp(buf + s, "void", 4) == 0:
return llvmlite.Void(pool)
# double
if ty_len == 6 and string.strncmp(buf + s, "double", 6) == 0:
return llvmlite.Double(pool)
# float
if ty_len == 5 and string.strncmp(buf + s, "float", 5) == 0:
return llvmlite.Float(pool)
# iN (i8, i16, i32, i64)
if ty_len >= 2 and buf[s] == 'i':
bits: int = 0
di: t.CSizeT = s + 1
valid: int = 1
while di < e:
d: int = buf[di]
if d >= '0' and d <= '9':
bits = bits * 10 + (d - '0')
else:
valid = 0
break
di += 1
if valid != 0 and bits > 0:
if bits == 8:
return llvmlite.Int8(pool)
if bits == 16:
return llvmlite.Int16(pool)
if bits == 32:
return llvmlite.Int32(pool)
if bits == 64:
return llvmlite.Int64(pool)
# 无法解析
return None
# ============================================================
# _LookupMethodRetTyFromTextLL - 从依赖模块的 text.ll 查找方法返回类型
#
# 读取 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll (level=1),搜索
# define 行中包含 "{sha1}.{class_name}.{method_name}" 的函数,
# 提取返回类型并转换为 llvmlite.LLVMType。
#
# 解决问题: 旧实现 _infer_method_ret_ty(已移除)默认返回 i32,导致指针返回值
# 被 inttoptr 截断为 32 位(coerce_to_type line 238-239)。
# 本函数从 text.ll 获取实际返回类型,避免截断。
#
# Args:
# pool: 内存池
# class_sha1: 类所属模块的 SHA1
# class_name: 类名
# method_name: 方法名
#
# Returns:
# LLVM 类型对象,或 None(未找到/text.ll 不存在)
# ============================================================
def _LookupMethodRetTyFromTextLL(self, pool: memhub.MemBuddy | t.CPtr,
class_sha1: str,
class_name: str,
method_name: str,
use_bare: int = 0) -> llvmlite.LLVMType | t.CPtr:
"""从依赖模块的 text.ll 中查找方法返回类型
use_bare: 1=按模块级函数查找(搜索 "{sha1}.{method_name}" define,
用于 new_lexer/tokenize 等模块函数;class_name 忽略)。
"""
if pool is None or class_sha1 is None or method_name is None:
return None
if self.TempDir is None or self.TempDirLen == 0:
return None
sha1_len: t.CSizeT = string.strlen(class_sha1)
if sha1_len < 2:
return None
# 构造 text.ll 路径 (level=1): {temp_dir}/{sha1[0:2]}/{sha1}.text.ll
# 使用 subdir 缓冲区避免 %c 格式化问题(与 StubMerger._sliced_path 一致)
path_len: t.CSizeT = self.TempDirLen + sha1_len + 14
path_buf: bytes = stdlib.malloc(path_len)
if path_buf is None:
return None
subdir_buf: bytes = stdlib.malloc(3)
if subdir_buf is None:
stdlib.free(path_buf)
return None
subdir_buf[0] = class_sha1[0]
subdir_buf[1] = class_sha1[1]
subdir_buf[2] = '\0'
viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll",
self.TempDir, subdir_buf, class_sha1)
stdlib.free(subdir_buf)
# 读取 text.ll
read_buf: bytes = stdlib.malloc(_TEXT_LL_READ_BUF_SIZE)
if read_buf is None:
stdlib.free(path_buf)
return None
tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
if tf.closed:
stdlib.free(path_buf)
stdlib.free(read_buf)
return None
text_len: t.CInt64T = tf.read_all(read_buf, _TEXT_LL_READ_BUF_SIZE)
tf.close()
stdlib.free(path_buf)
if text_len <= 0:
stdlib.free(read_buf)
return None
if text_len < _TEXT_LL_READ_BUF_SIZE:
read_buf[text_len] = '\0'
else:
read_buf[_TEXT_LL_READ_BUF_SIZE - 1] = '\0'
# 构造搜索模式: "{sha1}.{class_name}.{method_name}" 或 bare 模式 "{sha1}.{method_name}"
cls_len: t.CSizeT = 0
if class_name is not None:
cls_len = string.strlen(class_name)
meth_len: t.CSizeT = string.strlen(method_name)
search_len: t.CSizeT = sha1_len + meth_len + 2
if use_bare == 0:
search_len = sha1_len + cls_len + meth_len + 4
search_buf: bytes = stdlib.malloc(search_len)
if search_buf is None:
stdlib.free(read_buf)
return None
if use_bare != 0:
viperlib.snprintf(search_buf, search_len, "%s.%s",
class_sha1, method_name)
else:
viperlib.snprintf(search_buf, search_len, "%s.%s.%s",
class_sha1, class_name, method_name)
search_str_len: t.CSizeT = string.strlen(search_buf)
# 在 text.ll 中搜索 define 行包含 search_buf
buf_len: t.CSizeT = string.strlen(read_buf)
pos: t.CSizeT = 0
result_ty: llvmlite.LLVMType | t.CPtr = None
while pos < buf_len and result_ty is None:
ls: t.CSizeT = pos
le: t.CSizeT = pos
while le < buf_len:
if read_buf[le] == '\n':
break
le += 1
ll: t.CSizeT = le - ls
# 检查是否是 define 行
if ll >= 7 and string.strncmp(read_buf + ls, "define ", 7) == 0:
# 找 @ 符号
at_pos: t.CSizeT = ls + 7
while at_pos < ls + ll:
if read_buf[at_pos] == '@':
break
at_pos += 1
if at_pos < ls + ll:
# 跳过可选引号
name_start: t.CSizeT = at_pos + 1
if name_start < ls + ll and read_buf[name_start] == '"':
name_start += 1
# 检查是否匹配 search_buf
if name_start + search_str_len <= ls + ll:
if string.strncmp(read_buf + name_start, search_buf, search_str_len) == 0:
# 函数名边界检查:search 后必须是 '"'(带引号名)、'('(参数表)或行尾,
# 否则 "sha1.func" 会误匹配 "sha1.func_helper" 等前缀同名函数
name_end: t.CSizeT = name_start + search_str_len
end_ch: int = 0
if name_end < ls + ll:
end_ch = read_buf[name_end]
if end_ch == 34 or end_ch == 40 or end_ch == 0:
# 匹配!提取返回类型: [ls+7, at_pos)
result_ty = self._ParseLLVMRetTyStr(pool, read_buf, ls + 7, at_pos)
pos = le + 1
stdlib.free(search_buf)
stdlib.free(read_buf)
return result_ty
# ============================================================
# _dep_text_ll_exists - 探测依赖模块 text.ll 是否已生成
#
# 用于区分跨模块返回类型精确解析失败的两种场景:
# 1. text.ll 存在但函数未命中 → 真错误(依赖已编译,函数缺失)
# 2. text.ll 不存在 → 依赖模块尚未翻译(Phase A 按文件顺序翻译,
# main.vp 先于其 import 的 mbuddytest.vp),标记重试待下遍
# ============================================================
def _dep_text_ll_exists(self, pool: memhub.MemBuddy | t.CPtr,
sha1: str) -> int:
"""探测 {temp_dir}/{sha1[0:2]}/{sha1}.text.ll 是否存在,1=存在"""
if self.TempDir is None or self.TempDirLen == 0 or sha1 is None:
return 0
sha1_len: t.CSizeT = string.strlen(sha1)
if sha1_len < 2:
return 0
path_len: t.CSizeT = self.TempDirLen + sha1_len + 14
path_buf: bytes = stdlib.malloc(path_len)
subdir_buf: bytes = stdlib.malloc(3)
if path_buf is None or subdir_buf is None:
if path_buf is not None:
stdlib.free(path_buf)
if subdir_buf is not None:
stdlib.free(subdir_buf)
return 0
subdir_buf[0] = sha1[0]
subdir_buf[1] = sha1[1]
subdir_buf[2] = '\0'
viperlib.snprintf(path_buf, path_len, "%s/%s/%s.text.ll",
self.TempDir, subdir_buf, sha1)
stdlib.free(subdir_buf)
tf: fileio.File | t.CPtr = fileio.File(path_buf, fileio.MODE.R)
exists: int = 0
if not tf.closed:
tf.close()
exists = 1
stdlib.free(path_buf)
return exists
# ============================================================
# 属性方法(@property/@x.setter/@x.deleter)与静态/类方法调用辅助
#
# 元数据表由 HandlesClassDef 在类翻译/预注册阶段填充,
# 这里负责把 obj.prop / obj.prop=v / del obj.prop / Class.method()
# 翻译为对应的 {sha1}.ClassName.prop 系列函数调用。
# ============================================================
# ============================================================
# _translate_property_call — 翻译属性方法调用
#
# 与 _translate_method_call 的调用名/返回类型解析逻辑一致:
# 1. 优先用模块中已有的函数(精确/后缀匹配,来自 stub 注入)
# 2. 否则用类所属模块的 SHA1 构造 "{sha1}.ClassName.method" 调用名
# 3. 返回类型:函数实类型 → text.ll 查找 → 按方法名推断(默认 i32)
#
# call_head/call_count: 已构建好的参数链表(如 getter 只有 obj 一个参数)
# ============================================================
def _translate_property_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str,
method_name: str,
call_head: llvmlite.Value | t.CPtr,
call_count: int,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""翻译属性/静态方法调用,返回 call 结果 Value"""
if pool is None or builder is None or class_name is None or method_name is None:
return None
# 构造查找名: ClassName.method_name
lookup_name: t.CChar | t.CPtr = pool.alloc(128)
if lookup_name is None:
return None
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
# 查找函数(精确/后缀匹配)
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name)
# 确定调用名
call_name: str = lookup_name
if found_func is not None:
found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
if found_name is not None:
call_name = found_name
else:
# 未找到:用类所属模块的 SHA1 构造调用名
cls_sha1_pc: str = HandlesStruct.get_struct_sha1(class_name)
if cls_sha1_pc is not None:
mlen_pc: t.CSizeT = string.strlen(cls_sha1_pc) + string.strlen(lookup_name) + 2
mangled_pc: str = pool.alloc(mlen_pc)
if mangled_pc is not None:
viperlib.snprintf(mangled_pc, mlen_pc, "%s.%s", cls_sha1_pc, lookup_name)
call_name = mangled_pc
# 确定返回类型
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if found_func is not None:
frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
if frt is not None:
call_ret_ty = frt
else:
sp_ty1: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name)
if sp_ty1 is not None:
call_ret_ty = sp_ty1
else:
cls_sha1_rt: str = HandlesStruct.get_struct_sha1(class_name)
looked_up_ty: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
pool, cls_sha1_rt, class_name, method_name)
if looked_up_ty is not None:
call_ret_ty = looked_up_ty
else:
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
pool, cls_sha1_rt, class_name, method_name)
if vpi_ret_ty is not None:
call_ret_ty = vpi_ret_ty
else:
call_ret_ty = self._fail_method_ret_ty(method_name)
# 确保 declare 存在,然后调用
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, call_head, call_count)
return llvmlite.build_call(builder, call_name, call_head, call_count, call_ret_ty, 0)
# ============================================================
# _resolve_obj_class_name — 解析对象表达式的类名(短名)
#
# 优先从变量注解(AnnotClassName)解析(如 "memhub.MemBuddy" → "MemBuddy"),
# 失败时从 LLVM 类型解析(Ptr(Struct) → 类名)。
# 供属性访问/赋值/删除识别 property 时使用。
# ============================================================
def _resolve_obj_class_name(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
obj_node: ast.AST | t.CPtr) -> str:
"""解析对象表达式的类名(短名),失败返回 None"""
if pool is None or trans is None or obj_node is None:
return None
if obj_node.kind() == ast.ASTKind.Name:
obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(obj_node)
if obj_nm.id is not None:
var_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, obj_nm.id)
if var_entry is not None and var_entry.AnnotClassName is not None:
annot_val: str = var_entry.AnnotClassName
dot_ptr: t.CChar | t.CPtr = string.strrchr(annot_val, '.')
if dot_ptr is not None:
return dot_ptr + 1
return annot_val
return None
# ============================================================
# _try_property_getter_attr — 尝试将 obj.attr 翻译为 property getter 调用
#
# 检查 obj 的类是否有 @property/@x.getter 的 attr 方法;
# 若有则生成 call Class.attr(obj) 并返回调用结果 Value;否则返回 None。
# ============================================================
def _try_property_getter_attr(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
at_node: ast.Attribute | t.CPtr,
obj_ptr: llvmlite.Value | t.CPtr,
trans: HT.Translator | t.CPtr,
fallback_class_name: str = None) -> llvmlite.Value | t.CPtr:
"""尝试 property getter 属性访问,返回调用结果 Value;非 getter 返回 None
fallback_class_name: 对象表达式非 Name 时从 LLVM 类型解析出的类名兜底。
"""
if at_node is None or at_node.attr is None or obj_ptr is None or trans is None:
return None
class_name: str = self._resolve_obj_class_name(pool, trans, at_node.value)
if class_name is None:
class_name = fallback_class_name
if class_name is None:
return None
meta: int = HandlesClassDef.lookup_method_meta(class_name, at_node.attr)
if meta & HandlesClassDef.META_PROP_GETTER == 0:
return None
# 单参数调用: obj → getter
llvmlite.value_set_next(obj_ptr, None)
return self._translate_property_call(
pool, builder, mod, class_name, at_node.attr, obj_ptr, 1, trans)
# ============================================================
# _try_property_setter — 尝试将 obj.attr = v 翻译为 property setter 调用
#
# 检查 obj 的类是否有 @x.setter 的 attr 方法;
# 若有则生成 call Class.attr$set(obj, v),返回 1;否则返回 0。
# ============================================================
def _try_property_setter(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
target_attr: ast.Attribute | t.CPtr,
rhs_val: llvmlite.Value | t.CPtr,
trans: HT.Translator | t.CPtr) -> int:
"""尝试 property setter 赋值,返回 1=已处理(生成调用)"""
if pool is None or builder is None or mod is None or trans is None:
return 0
if target_attr is None or target_attr.attr is None or rhs_val is None:
return 0
class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value)
if class_name is None:
return 0
meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr)
if meta & HandlesClassDef.META_PROP_SETTER == 0:
return 0
# 翻译对象值(self 参数)
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, target_attr.value, None, 0, trans)
if obj_val is None:
return 0
# 构建参数链表: obj → rhs
llvmlite.value_set_next(obj_val, None)
llvmlite.value_set_next(rhs_val, None)
llvmlite.value_set_next(obj_val, rhs_val)
# setter 函数名带 $set 后缀
setter_name_buf: t.CChar | t.CPtr = pool.alloc(128)
if setter_name_buf is None:
return 0
viperlib.snprintf(setter_name_buf, 128, "%s$set", target_attr.attr)
self._translate_property_call(pool, builder, mod, class_name,
setter_name_buf, obj_val, 2, trans)
return 1
# ============================================================
# _try_property_deleter — 尝试将 del obj.attr 翻译为 property deleter 调用
#
# 检查 obj 的类是否有 @x.deleter 的 attr 方法;
# 若有则生成 call Class.attr$del(obj),返回 1;否则返回 0。
# ============================================================
def _try_property_deleter(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
target_attr: ast.Attribute | t.CPtr,
trans: HT.Translator | t.CPtr) -> int:
"""尝试 property deleter 删除,返回 1=已处理(生成调用)"""
if pool is None or builder is None or mod is None or trans is None:
return 0
if target_attr is None or target_attr.attr is None:
return 0
class_name: str = self._resolve_obj_class_name(pool, trans, target_attr.value)
if class_name is None:
return 0
meta: int = HandlesClassDef.lookup_method_meta(class_name, target_attr.attr)
if meta & HandlesClassDef.META_PROP_DELETER == 0:
return 0
# 翻译对象值(self 参数)
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, target_attr.value, None, 0, trans)
if obj_val is None:
return 0
llvmlite.value_set_next(obj_val, None)
# deleter 函数名带 $del 后缀
del_name_buf: t.CChar | t.CPtr = pool.alloc(128)
if del_name_buf is None:
return 0
viperlib.snprintf(del_name_buf, 128, "%s$del", target_attr.attr)
self._translate_property_call(pool, builder, mod, class_name,
del_name_buf, obj_val, 1, trans)
return 1
# ============================================================
# _translate_static_class_call — 翻译 ClassName.method(args) 静态/类方法调用
#
# @staticmethod: 直接 call Class.method(args...),无 self
# @classmethod: 在参数前插入栈上分配的类实例指针(与 TPC 一致)
# ============================================================
def _translate_static_class_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str,
method_name: str,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""翻译类名静态/类方法调用,返回 call 结果 Value;非静态/类方法返回 None"""
if pool is None or builder is None or mod is None or trans is None:
return None
if class_name is None or method_name is None or cl is None:
return None
meta: int = HandlesClassDef.lookup_method_meta(class_name, method_name)
is_static: int = 0
is_class: int = 0
if meta & HandlesClassDef.META_STATIC != 0:
is_static = 1
if meta & HandlesClassDef.META_CLASS != 0:
is_class = 1
if is_static == 0 and is_class == 0:
return None
# 构建参数链表
head: llvmlite.Value | t.CPtr = None
total_count: int = 0
# @classmethod: 插入栈上分配的类实例指针作为 cls 参数
if is_class != 0:
struct_ty_cc: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(class_name)
if struct_ty_cc is None:
return None
cls_ptr: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty_cc)
if cls_ptr is None:
return None
llvmlite.value_set_next(cls_ptr, None)
head = cls_ptr
total_count = 1
# 翻译调用参数
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
can: t.CSizeT = 0
if cargs is not None:
can = cargs.__len__()
tail: llvmlite.Value | t.CPtr = head
for ai in range(can):
arg_node: ast.AST | t.CPtr = cargs.get(ai)
if arg_node is None:
continue
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg_node, None, 0, trans)
if arg_val is None:
continue
llvmlite.value_set_next(arg_val, None)
if head is None:
head = arg_val
tail = arg_val
else:
llvmlite.value_set_next(tail, arg_val)
tail = arg_val
total_count += 1
if head is None:
return None
return self._translate_property_call(pool, builder, mod, class_name,
method_name, head, total_count, trans)
# ============================================================
# _translate_method_call - 翻译方法调用 obj.method(args)
#
# 生成: call <ret_ty> @SHA1.ClassName.method_name(Ptr(StructTy) %obj, args...)
#
# obj_ptr 是对象变量的 alloca(Ptr(StructTy)),作为 self 参数传入
# ============================================================
def _translate_method_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str,
method_name: str,
obj_ptr: llvmlite.Value | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""翻译方法调用,返回 call 结果 Value"""
if pool is None or builder is None or class_name is None or method_name is None:
return None
if obj_ptr is None or cl is None:
return None
# 提前获取结构体 entry(用 find_struct_by_type 规避跨模块同名 find_struct 找错)
# 用于继承链遍历、SHA1 查找和虚表分派
mc_entry: HandlesStruct.StructEntry | t.CPtr = None
mc_struct_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(obj_ptr)
if mc_struct_ty is not None:
mc_entry = HandlesStruct.find_struct_by_type(mc_struct_ty)
if mc_entry is None:
mc_entry = HandlesStruct.find_struct(class_name)
# 构造方法查找名: ClassName.method_name
lookup_name: t.CChar | t.CPtr = pool.alloc(128)
if lookup_name is None:
return None
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, method_name)
# 查找函数(支持 SHA1 后缀匹配)
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, lookup_name)
# 泛型模板类方法:特化函数名带类型参数({sha1}.list[int].get),
# "ClassName.method" 短名匹配不到。特化由触发方(通常即调用方)模块完成,
# 用对象实际特化名(mc_entry.Name)构造后缀匹配,获得精确返回类型。
if found_func is None and mc_entry is not None and mc_entry.Name is not None:
if string.strcmp(mc_entry.Name, class_name) != 0:
spec_lookup: t.CChar | t.CPtr = pool.alloc(160)
if spec_lookup is not None:
viperlib.snprintf(spec_lookup, 160, "%s.%s", mc_entry.Name, method_name)
found_func = self.find_func_in_module(mod, spec_lookup)
# 沿 MRO 祖先链查找父类方法(子类未覆盖时回退到父类,先声明父类优先)
mc_anc: str = None # 方法实际定义类(多继承 this 调整用)
if found_func is None:
mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
mi: int = 1
while mro_ptr is not None and mro_ptr[mi] != 0:
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
if anc is not None:
parent_lookup: t.CChar | t.CPtr = pool.alloc(128)
if parent_lookup is not None:
viperlib.snprintf(parent_lookup, 128, "%s.%s", anc, method_name)
parent_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, parent_lookup)
if parent_func is not None:
found_func = parent_func
mc_anc = anc
break
mi += 1
# 确定调用名
call_name: str = lookup_name
if found_func is not None:
found_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
if found_name is not None:
call_name = found_name
else:
# found_func 为 None(stub 未注入):用类所属模块的 SHA1 构造调用名
# 沿继承链查找第一个有 SHA1 的类
cls_sha1_mc: str = None
if mc_entry is not None:
cls_sha1_mc = mc_entry.ModuleSha1
else:
cls_sha1_mc = HandlesStruct.get_struct_sha1(class_name)
if cls_sha1_mc is None:
mro_p: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
mj: int = 1
while mro_p is not None and mro_p[mj] != 0 and cls_sha1_mc is None:
anc_p: str = (str | t.CPtr)(t.CVoid(mro_p[mj], t.CPtr))
if anc_p is not None:
cls_sha1_mc = HandlesStruct.get_struct_sha1(anc_p)
mj += 1
if cls_sha1_mc is not None:
mangled_len_mc: t.CSizeT = string.strlen(cls_sha1_mc) + string.strlen(lookup_name) + 2
mangled_mc: str = pool.alloc(mangled_len_mc)
if mangled_mc is not None:
viperlib.snprintf(mangled_mc, mangled_len_mc, "%s.%s", cls_sha1_mc, lookup_name)
call_name = mangled_mc
# 确定返回类型
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
call_ret_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if found_func is not None:
frt: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
if frt is not None:
call_ret_ty = frt
else:
# found_func 为 None(stub 未注入):先处理编译器内置特殊方法
sp_ty2: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, class_name, method_name)
if sp_ty2 is not None:
call_ret_ty = sp_ty2
else:
# 泛型特化方法调用:特化函数可能尚未注册(如 ast.base 用
# list[AST|t.CPtr].get)。主动触发特化(幂等,MethodsEmitted 防重入),
# 特化后重新查找即可命中,返回类型来自特化函数定义(天然精确)。
gen_done: int = 0
if class_name is not None:
lbkt_g: str = string.strchr(class_name, '[')
if lbkt_g is not None:
rbkt_g: str = string.strrchr(class_name, ']')
if rbkt_g is not None and rbkt_g > lbkt_g:
base_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(lbkt_g) - t.CUInt64T(class_name))
arg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(rbkt_g) - t.CUInt64T(lbkt_g) - 1)
if base_len_g > 0 and arg_len_g > 0:
base_buf_g: str = pool.alloc(base_len_g + 1)
arg_buf_g: str = pool.alloc(arg_len_g + 1)
if base_buf_g is not None and arg_buf_g is not None:
string.strncpy(base_buf_g, class_name, base_len_g)
base_buf_g[base_len_g] = '\0'
string.strncpy(arg_buf_g, lbkt_g + 1, arg_len_g)
arg_buf_g[arg_len_g] = '\0'
ta_list_g: list[str] | t.CPtr = list[str](pool, 8)
if ta_list_g is not None:
# 逗号分隔多类型实参(list[X] / dict[K, V])
cur_arg_g: str = arg_buf_g
while cur_arg_g is not None:
comma_g: str = string.strchr(cur_arg_g, ',')
if comma_g is None:
ta_list_g.append(cur_arg_g)
break
seg_len_g: t.CSizeT = t.CSizeT(t.CUInt64T(comma_g) - t.CUInt64T(cur_arg_g))
seg_buf_g: str = pool.alloc(seg_len_g + 1)
if seg_buf_g is not None:
string.strncpy(seg_buf_g, cur_arg_g, seg_len_g)
seg_buf_g[seg_len_g] = '\0'
ta_list_g.append(seg_buf_g)
cur_arg_g = comma_g + 1
spec_name_g: str = HandlesClassDef._specialize_generic_class(
trans, base_buf_g, ta_list_g)
if spec_name_g is not None:
# 特化后重新查找特化函数(特化名 = 调用点类名)
spec_lk_g: str = pool.alloc(
string.strlen(class_name) + string.strlen(method_name) + 2)
if spec_lk_g is not None:
viperlib.snprintf(spec_lk_g,
string.strlen(class_name) + string.strlen(method_name) + 2,
"%s.%s", class_name, method_name)
spec_found_g: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, spec_lk_g)
if spec_found_g is not None:
frt_g: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(spec_found_g)
if frt_g is not None:
call_ret_ty = frt_g
found_func = spec_found_g
gen_done = 1
if gen_done == 0:
# 尝试从 text.ll 查找实际返回类型
# 避免指针返回值被默认 i32 导致 inttoptr 截断
looked_up_ty: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
pool, cls_sha1_mc, class_name, method_name)
if looked_up_ty is not None:
call_ret_ty = looked_up_ty
else:
# 精确查找:vpi stub 返回注解缓存(方法定义处,不硬编码白名单)
vpi_ret_ty: llvmlite.LLVMType | t.CPtr = self._lookup_method_ret_ty_via_vpi(
pool, cls_sha1_mc, class_name, method_name)
if vpi_ret_ty is not None:
call_ret_ty = vpi_ret_ty
else:
call_ret_ty = self._fail_method_ret_ty(method_name, cl)
# 翻译调用参数
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
can: t.CSizeT = 0
if cargs is not None:
can = cargs.__len__()
kw_calls: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords
kwc: t.CSizeT = 0
if kw_calls is not None:
kwc = kw_calls.__len__()
# 多继承 this 调整(字节偏移法,2026-08-10,与 TPC HandlesExprCall._adjust_this_for_inherited_method 一致):
# 继承方法体按"定义类自身布局"读 self 字段(如 B.get_b 内 GEP(self_B, [0,1])
# 的字节偏移是 B 布局中 b 的 offset 12)。父类字段区在子类中的字节偏移可能
# 不同(如 AB={vtable,a@8,b@12} 中 b 偏移 16),self 需按字节差前移,使父类
# 方法内二次 GEP 恰好落到子类字段。
# delta = 字段在子类中字节偏移 − 字段在父类自身布局中字节偏移
# delta==0(第一父类,字段区前缀对齐)无需调整;delta>0 时按字节 GEP 到
# 父类字段区在子类中的等效基址,再 bitcast 成父类指针。
# 原实现仅覆盖"无 vtable 的父类"(其首字段偏移 0,GEP 到首字段即父类起点),
# 且用 GEP 字段法——对 vtable 父类(首字段偏移非 0,如 B)被直接跳过不调整
# → AB 场景 B.get_b 按 B 布局读 self.b@12 落到 a → AB 字段/方法 FAILED。
self_arg: llvmlite.Value | t.CPtr = obj_ptr
if mc_anc is not None and string.strcmp(mc_anc, class_name) != 0:
anc_entry_th: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(mc_anc)
if anc_entry_th is not None and anc_entry_th.FieldCount > 0:
anc_first_name_th: str = None
afi_th: int = 0
while afi_th < anc_entry_th.FieldCount:
afe_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
anc_entry_th, afi_th)
if afe_th is not None:
afn_th: str = HandlesStruct.get_field_name_ptr(afe_th)
if afn_th is not None and string.strcmp(afn_th, "__vtable__") != 0:
anc_first_name_th = afn_th
break
afi_th += 1
if anc_first_name_th is not None:
sub_entry_th: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(
class_name)
if sub_entry_th is not None:
anc_field_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
anc_entry_th.Ty, anc_first_name_th)
sub_field_th: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
sub_entry_th.Ty, anc_first_name_th)
if anc_field_th is not None and sub_field_th is not None:
anc_off_th: int = self._field_byte_offset(
pool, anc_entry_th, anc_field_th.Index)
sub_off_th: int = self._field_byte_offset(
pool, sub_entry_th, sub_field_th.Index)
delta_th: int = sub_off_th - anc_off_th
if delta_th > 0:
i8_ty_th: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_th: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_th)
obj_i8_th: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, obj_ptr, i8_ptr_th)
delta_val_th: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, delta_th)
adj_th: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i8_ty_th, obj_i8_th, delta_val_th)
if adj_th is not None:
anc_ptr_ty_th: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, anc_entry_th.Ty)
self_arg = llvmlite.build_bitcast(builder, adj_th, anc_ptr_ty_th)
# 构建参数链表: self → arg1 → arg2 → ...
llvmlite.value_set_next(self_arg, None)
head: llvmlite.Value | t.CPtr = self_arg
tail: llvmlite.Value | t.CPtr = self_arg
arg_count_eff: int = 0
if kwc > 0 and found_func is not None:
# 关键字参数:遍历函数定义参数(跳过 self),位置参数优先,其余按名匹配
# 缺失参数用零值兜底,保持 call 参数数量与 define 一致
cur_param_k: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
if cur_param_k is not None:
cur_param_k = llvmlite.param_get_next(cur_param_k) # 跳过 self
pi_k: int = 0
while cur_param_k is not None:
arg_node_k: ast.AST | t.CPtr = None
if pi_k < can:
arg_node_k = cargs.get(pi_k)
else:
pname_k: t.CChar | t.CPtr = llvmlite.param_get_name(cur_param_k)
if pname_k is not None:
ki_k: int
for ki_k in range(kwc):
kw_k: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(kw_calls.get(ki_k))
if kw_k is None or kw_k.arg is None or kw_k.value is None:
continue
if self._kwarg_name_matches(kw_k.arg, pname_k) == 1:
arg_node_k = kw_k.value
break
arg_val_k: llvmlite.Value | t.CPtr = None
if arg_node_k is not None:
arg_val_k = HandlesExpr.translate_value(
builder, pool, mod, arg_node_k, None, 0, trans)
if arg_val_k is None:
# 缺失参数:零值兜底(保持参数数量匹配)
pty_k: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k)
if pty_k is not None:
arg_val_k = llvmlite.ConstZero(pool, pty_k)
if arg_val_k is not None:
pty_k2: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur_param_k)
if pty_k2 is not None:
arg_val_k = HandlesExpr.coerce_to_type(
builder, arg_val_k, pty_k2, arg_node_k)
llvmlite.value_set_next(arg_val_k, None)
llvmlite.value_set_next(tail, arg_val_k)
tail = arg_val_k
arg_count_eff += 1
pi_k += 1
cur_param_k = llvmlite.param_get_next(cur_param_k)
else:
# 位置参数(原逻辑)
for ai in range(can):
arg_node: ast.AST | t.CPtr = cargs.get(ai)
if arg_node is None:
continue
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg_node, None, 0, trans)
if arg_val is None:
continue
# 按形参类型 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1)
# 修复: CDefine/i32 常量传给 i64 形参(如 MemBuddy.__init__ 的 size: t.CSizeT)
# 未提升导致 call(i32) 与 define(i64) 不匹配,运行时读到垃圾高 32 位崩溃
if found_func is not None:
pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
pi: int = 0
while pp is not None and pi < ai + 1:
if pi == ai + 1:
break
pp = llvmlite.param_get_next(pp)
pi += 1
if pp is not None:
pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp)
if pty is not None:
arg_val = HandlesExpr.coerce_to_type(
builder, arg_val, pty, arg_node)
llvmlite.value_set_next(arg_val, None)
llvmlite.value_set_next(tail, arg_val)
tail = arg_val
arg_count_eff += 1
total_count: int = 1 + arg_count_eff
# 默认参数填充:如果调用点参数少于函数定义参数,用默认值填充缺失参数
# 查找函数的 defaults 信息
mdf_defaults: t.CVoid | t.CPtr = None
mdf_default_count: int = 0
mdf_param_count: int = 0
if trans is not None and trans._funcs is not None:
mdf_entry: FuncEntry | t.CPtr = HandlesExprCall.find_func_entry_in_table(
trans._funcs, trans._func_count, lookup_name)
if mdf_entry is not None:
mdf_defaults = mdf_entry.Defaults
mdf_default_count = mdf_entry.DefaultCount
mdf_param_count = mdf_entry.ParamCount
if mdf_defaults is None:
mdf_gd: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(lookup_name)
if mdf_gd is not None:
mdf_defaults = mdf_gd.Defaults
mdf_default_count = mdf_gd.DefaultCount
mdf_param_count = mdf_gd.ParamCount
# 计算需要填充的参数(不含 self)
# arg_count_eff = 已提供的非 self 参数数量(含关键字模式完整构建)
# mdf_param_count = 函数定义的非 self 参数数量
if mdf_param_count > arg_count_eff:
mdf_offset: int = mdf_param_count - mdf_default_count
mdf_pi: int = arg_count_eff
while mdf_pi < mdf_param_count:
# 优先用默认值
if mdf_defaults is not None and mdf_default_count > 0 and mdf_pi >= mdf_offset:
mdf_di: int = mdf_pi - mdf_offset
if mdf_di < mdf_default_count:
# 用 stdlib 常量快照重建(mdf_gd.Defaults 的 pool 内 AST 可能已被 reset 回收,
# 直接回退读 AST 会 use-after-free——快照失败时 fail-fast 暴露,绝不读悬空 AST)
mdf_val: llvmlite.Value | t.CPtr = None
if mdf_gd is not None:
mdf_val = HandlesExprCall._build_const_from_snapshot(
pool, mod, mdf_gd, mdf_di, trans, builder)
if mdf_val is None:
HandlesType.fatal_error(
cl,
f"跨模块默认参数无法重建(快照缺失,默认值需为简单常量): {lookup_name}",
"TypeError")
continue
llvmlite.value_set_next(mdf_val, None)
llvmlite.value_set_next(tail, mdf_val)
tail = mdf_val
total_count += 1
mdf_pi += 1
continue
# 无默认值时用零值兜底(需要 found_func 获取参数类型)
if found_func is not None:
param_node_z: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
skip_z: int = 0
while skip_z <= mdf_pi and param_node_z is not None:
param_node_z = llvmlite.param_get_next(param_node_z)
skip_z += 1
if param_node_z is not None:
zero_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(param_node_z)
zero_val: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, zero_ty)
if zero_val is not None:
llvmlite.value_set_next(zero_val, None)
llvmlite.value_set_next(tail, zero_val)
tail = zero_val
total_count += 1
mdf_pi += 1
# 虚方法分发:如果类有虚表且该方法在虚表中,走间接调用
# (不依赖 found_func — 继承的虚方法可能没有子类实现)
# 复用前面已获取的 mc_entry(find_struct_by_type 规避跨模块同名找错)
mc_has_vt: int = 0
mc_method_idx: int = -1
if mc_entry is not None:
mc_has_vt = mc_entry.HasVTable
if mc_has_vt == 1 and mc_entry.VTableMethods is not None:
mc_methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(mc_entry.VTableMethods, t.CPtr))
for mc_mi in range(mc_entry.VTableMethodCount):
mc_mname_addr: t.CSizeT = mc_methods_arr[mc_mi]
if mc_mname_addr == 0:
continue
mc_mname: str = (str | t.CPtr)(t.CVoid(mc_mname_addr, t.CPtr))
if mc_mname is not None and string.strcmp(mc_mname, method_name) == 0:
mc_method_idx = mc_mi
break
if mc_has_vt == 1 and mc_method_idx >= 0:
# 虚分派 self 必须用调整后的 self_arg(多继承 this 调整),
# 否则 B.get_b 收到未调整的 AB*,方法体内按 B 布局读字段错位。
# vtable 读取必须用对象头 obj_ptr(调整后 self 头部是父类字段值)。
return self._do_virtual_call(pool, builder, mod, class_name, method_name,
self_arg, head, total_count, found_func, call_ret_ty,
obj_ptr)
# 跨模块调用:创建 declare 声明,避免 llc 报 undefined value
self._ensure_method_declare(pool, mod, call_name, call_ret_ty, head, total_count)
# 检查变长函数 + C ABI 提升
is_variadic_3441: int = HandlesExprCall._check_and_promote_variadic_call(pool, builder, mod, call_name, head, total_count)
return llvmlite.build_call(builder, call_name, head, total_count, call_ret_ty, is_variadic_3441)
# ============================================================
# _translate_super_call — super().method(args) → 静态调用父类方法
#
# Python super 语义(2026-08-10 实现):
# - 当前类来自 self.CurClassName(_translate_method 翻译方法体时设置)
# - 父类查找:沿 get_mro_chain(CurClassName) 跳过自身,找第一个定义 method 的祖先
# - self 指针:符号表 self 变量 alloca load(对象头,复用 c.Addr(self) 模式)
# - this_adjust:父类字段区在子类中字节偏移 delta>0 时 GEP i8* + delta
# (复用 _field_byte_offset 字节偏移法,与 _translate_method_call 一致)
# - 静态调用父类实现:不虚分派(super() 不触发子类 override)
# ============================================================
def _translate_super_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
method_name: str,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""super().method(args) → 父类方法静态调用,返回 call 结果 Value"""
if pool is None or builder is None or cl is None or method_name is None:
return None
if trans is None:
return None
# 1. 当前方法所属类:从 self 变量的注解类名获取(_translate_method
# 注册 self 时 set_var_annot_class_name(SymTab, "self", class_name))。
# 不用 Mixin 字段:TPV Mixin 字段按声明类独立布局(Generator 多继承
# 去重只保留首个声明),ClassGenMixin 写的 CurClassName 与 CallGenMixin
# 读的位置偏移不一致 → 运行时读到空 → super() 误报"只能在类方法内使用"。
self_entry: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, "self")
if self_entry is None:
self_entry = HandlesVar.lookup_var_entry(trans.SymTab, "cls")
if self_entry is None:
HandlesType.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError")
return None
cur_class: str = self_entry.AnnotClassName
if cur_class is None:
HandlesType.fatal_error(cl, "super() 只能在类方法内使用(self 无注解类名)")
return None
# 2. 沿 MRO 跳过自身,找第一个定义 method 的祖先类
anc: str = None
mro_sp: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, cur_class)
mi_sp: int = 1
while mro_sp is not None and mro_sp[mi_sp] != 0:
anc_sp: str = (str | t.CPtr)(t.CVoid(mro_sp[mi_sp], t.CPtr))
if anc_sp is not None:
probe_sp: t.CChar | t.CPtr = pool.alloc(160)
if probe_sp is not None:
viperlib.snprintf(probe_sp, 160, "%s.%s", anc_sp, method_name)
if HandlesExprCall.find_func_global(probe_sp) is not None:
anc = anc_sp
break
mi_sp += 1
if anc is None:
err_sp: t.CChar | t.CPtr = pool.alloc(256)
if err_sp is not None:
viperlib.snprintf(err_sp, 256, "super(): 当前类 %s 的父类链未定义方法 %s",
cur_class, method_name)
HandlesType.fatal_error(cl, err_sp, "TypeError")
HandlesType.fatal_error(cl, "super(): 父类链未定义方法", "TypeError")
return None
# 3. self 指针(self 变量 alloca load,复用 c.Addr(self) 模式)
if self_entry.Alloca is None or self_entry.Alloca.Ty is None:
HandlesType.fatal_error(cl, "super(): 当前作用域无 self 变量(静态方法内不可用)", "TypeError")
return None
self_ptr: llvmlite.Value | t.CPtr = None
match self_entry.Alloca.Ty:
case llvmlite.LLVMType.Ptr(inner1):
match inner1:
case llvmlite.LLVMType.Ptr(inner2):
obj_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, inner2)
self_ptr = llvmlite.build_load(builder, obj_ty_sp, self_entry.Alloca)
case _:
self_ptr = llvmlite.build_load(builder, self_entry.Alloca.Ty, self_entry.Alloca)
case _:
self_ptr = self_entry.Alloca
if self_ptr is None:
return None
# 3. this_adjust(字节偏移法:父类字段区在子类中的偏移差)
self_arg: llvmlite.Value | t.CPtr = self_ptr
if string.strcmp(anc, cur_class) != 0:
anc_entry_sp: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(anc)
if anc_entry_sp is not None and anc_entry_sp.FieldCount > 0:
first_name_sp: str = None
afi_sp: int = 0
while afi_sp < anc_entry_sp.FieldCount:
afe_sp: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._get_field_entry(
anc_entry_sp, afi_sp)
if afe_sp is not None:
afn_sp: str = HandlesStruct.get_field_name_ptr(afe_sp)
if afn_sp is not None and string.strcmp(afn_sp, "__vtable__") != 0:
first_name_sp = afn_sp
break
afi_sp += 1
if first_name_sp is not None:
sub_entry_sp: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(
cur_class)
if sub_entry_sp is not None:
anc_field_sp: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
anc_entry_sp.Ty, first_name_sp)
sub_field_sp: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field(
sub_entry_sp.Ty, first_name_sp)
if anc_field_sp is not None and sub_field_sp is not None:
anc_off_sp: int = self._field_byte_offset(
pool, anc_entry_sp, anc_field_sp.Index)
sub_off_sp: int = self._field_byte_offset(
pool, sub_entry_sp, sub_field_sp.Index)
delta_sp: int = sub_off_sp - anc_off_sp
if delta_sp > 0:
i8_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_sp)
obj_i8_sp: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, self_ptr, i8_ptr_sp)
dval_sp: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, delta_sp)
adj_sp: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i8_ty_sp, obj_i8_sp, dval_sp)
if adj_sp is not None:
anc_ptr_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, anc_entry_sp.Ty)
self_arg = llvmlite.build_bitcast(builder, adj_sp, anc_ptr_sp)
# 4. 查找父类方法函数 + 构造调用名(SHA1 mangled)
anc_lookup: t.CChar | t.CPtr = pool.alloc(160)
if anc_lookup is None:
return None
viperlib.snprintf(anc_lookup, 160, "%s.%s", anc, method_name)
found_func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, anc_lookup)
call_name: str = anc_lookup
anc_sha1_sp: str = HandlesStruct.get_struct_sha1(anc)
if anc_sha1_sp is None:
anc_sha1_sp = trans.ModuleSha1
if found_func is not None:
fname_sp: t.CChar | t.CPtr = llvmlite.function_get_name(found_func)
if fname_sp is not None:
call_name = fname_sp
else:
if anc_sha1_sp is not None:
mangled_sp: str = HandlesFunctions._mangle_name_with_sha1(anc_sha1_sp, anc_lookup)
if mangled_sp is not None:
call_name = mangled_sp
# 5. 翻译参数 + 按形参 coerce(self 是形参 0,第 ai 个实参对应形参 ai+1)
cargs_sp: list[ast.AST | t.CPtr] | t.CPtr = cl.args
can_sp: t.CSizeT = 0
if cargs_sp is not None:
can_sp = cargs_sp.__len__()
llvmlite.value_set_next(self_arg, None)
head: llvmlite.Value | t.CPtr = self_arg
tail: llvmlite.Value | t.CPtr = self_arg
arg_count_sp: int = 1
for ai_sp in range(can_sp):
arg_node_sp: ast.AST | t.CPtr = cargs_sp.get(ai_sp)
if arg_node_sp is None:
continue
arg_val_sp: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg_node_sp, None, 0, trans)
if arg_val_sp is None:
continue
if found_func is not None:
pp_sp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(found_func)
pi_sp: int = 0
while pp_sp is not None and pi_sp < ai_sp + 1:
if pi_sp == ai_sp + 1:
break
pp_sp = llvmlite.param_get_next(pp_sp)
pi_sp += 1
if pp_sp is not None:
pty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(pp_sp)
if pty_sp is not None:
arg_val_sp = HandlesExpr.coerce_to_type(
builder, arg_val_sp, pty_sp, arg_node_sp)
llvmlite.value_set_next(arg_val_sp, None)
llvmlite.value_set_next(tail, arg_val_sp)
tail = arg_val_sp
arg_count_sp += 1
# 6. 返回类型:found_func → 特殊方法 → text.ll/vpi
ret_ty_sp: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
if found_func is not None:
frt_sp: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(found_func)
if frt_sp is not None:
ret_ty_sp = frt_sp
else:
sp_ty_sp: llvmlite.LLVMType | t.CPtr = self._special_method_ret_ty(pool, anc, method_name)
if sp_ty_sp is not None:
ret_ty_sp = sp_ty_sp
else:
looked_sp: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL(
pool, anc_sha1_sp, anc, method_name)
if looked_sp is not None:
ret_ty_sp = looked_sp
# 7. 跨模块:创建 declare;生成 call
if found_func is None:
self._ensure_method_declare(pool, mod, call_name, ret_ty_sp, head, arg_count_sp)
is_variadic_sp: int = HandlesExprCall._check_and_promote_variadic_call(
pool, builder, mod, call_name, head, arg_count_sp)
return llvmlite.build_call(builder, call_name, head, arg_count_sp, ret_ty_sp, is_variadic_sp)
# ============================================================
# _field_byte_offset — 计算字段在结构体布局中的字节偏移
#
# 按 LLVM 布局遍历 struct elements 带对齐累加(与 ClassGenMixin._get_type_size
# 的 padding 规则一致)。field_index 是 FieldEntry.Index(OOP 类 __vtable__ 占 0)。
# 供多继承 this 调整(字节偏移法)计算 delta。
# ============================================================
def _field_byte_offset(self, pool: memhub.MemBuddy | t.CPtr,
entry: HandlesStruct.StructEntry | t.CPtr,
field_index: int) -> int:
"""计算字段在结构体中的字节偏移(含对齐 padding),无法计算返回 0"""
if pool is None or entry is None or entry.Ty is None or field_index < 0:
return 0
match entry.Ty:
case llvmlite.LLVMType.Struct(fields, fcount, name):
offset_fb: int = 0
cur_fb: llvmlite.ParamNode | t.CPtr = fields
i_fb: int = 0
while cur_fb is not None and i_fb < field_index:
if cur_fb.Ty is not None:
fty_fb: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur_fb.Ty)
fsize_fb: int = HandlesClassDef._get_type_size(fty_fb)
falign_fb: int = HandlesClassDef._get_type_align(fty_fb)
if falign_fb > 1:
rem_fb: int = offset_fb % falign_fb
if rem_fb != 0:
offset_fb += falign_fb - rem_fb
offset_fb += fsize_fb
cur_fb = cur_fb.Next
i_fb += 1
# 字段自身对齐
if cur_fb is not None and cur_fb.Ty is not None:
fty2_fb: llvmlite.LLVMType | t.CPtr = (llvmlite.LLVMType | t.CPtr)(cur_fb.Ty)
falign2_fb: int = HandlesClassDef._get_type_align(fty2_fb)
if falign2_fb > 1:
rem2_fb: int = offset_fb % falign2_fb
if rem2_fb != 0:
offset_fb += falign2_fb - rem2_fb
return offset_fb
case _:
return 0
# ============================================================
# _kwarg_name_matches — 检查关键字参数名是否匹配函数参数名
#
# 函数参数名在 LLVM IR 中带 % 前缀(如 "%a"),关键字参数名无前缀(如 "a")
# 跳过 % 前缀后逐字符比较
# ============================================================
def _kwarg_name_matches(self, kw_arg: str,
param_name: t.CChar | t.CPtr) -> int:
"""检查关键字参数名 kw_arg 是否匹配参数名 param_name(跳过 % 前缀)"""
if kw_arg is None or param_name is None:
return 0
start: t.CSizeT = 0
if param_name[0] == '%':
start = 1
for i, ch in enumerate(kw_arg):
c: t.CChar = param_name[start + i]
if c == '\0' or c != ch:
return 0
if param_name[start + i + 1] != '\0':
return 0
return 1
# ============================================================
# _translate_struct_ctor_kw — 结构体构造函数(关键字参数)
#
# 支持两种语法:
# Point(x=10, y=20) — 全关键字
# Point(10, y=20) — 混合(位置 + 关键字)
#
# 位置参数按字段索引赋值,关键字参数按字段名查找赋值
# ============================================================
def _translate_struct_ctor_kw(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
struct_ty: llvmlite.LLVMType | t.CPtr,
class_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
keywords: list[ast.AST | t.CPtr] | t.CPtr,
kw_count: t.CSizeT,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""结构体构造函数(关键字参数版本)"""
# 创建临时 alloca
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty)
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
if tmp is None:
return llvmlite.ConstZero(pool, struct_ty)
# OOP 结构体:调用 __before_init__ 进行零值填充和默认值赋值
# 用 find_struct_by_type 规避跨模块同名 find_struct 找错
kw_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct_by_type(struct_ty)
is_oop: int = 0
if kw_entry is not None:
is_oop = kw_entry.IsOOP
# 跨模块 OOP 类推断:IsOOP 可能未设置(Phase1 缓存跳过 _translate_oop_methods)
# 方案1: 检查当前模块是否有 ClassName.__init__ 的声明(stub 注入)
# 方案2: 检查全局默认参数表是否有 ClassName.__init__ 的条目(翻译时填充,更可靠)
if is_oop == 0 and class_name is not None:
kw_init_lookup: t.CChar | t.CPtr = pool.alloc(128)
if kw_init_lookup is not None:
viperlib.snprintf(kw_init_lookup, 128, "%s.__init__", class_name)
# 方案1: 检查当前模块的函数声明
kw_init_found: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, kw_init_lookup)
if kw_init_found is not None:
is_oop = 1
if kw_entry is not None:
kw_entry.IsOOP = 1
kw_entry.HasInit = 1
else:
# 方案2: 检查全局默认参数表(翻译时填充,不依赖 stub 注入)
kw_init_defaults: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(kw_init_lookup)
if kw_init_defaults is not None:
is_oop = 1
if kw_entry is not None:
kw_entry.IsOOP = 1
kw_entry.HasInit = 1
if is_oop != 0:
self._call_method_on_ptr(pool, builder, mod, class_name,
"__before_init__", tmp, None, 0, trans)
else:
# 普通结构体:store zeroinitializer + 应用默认值
zero: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty)
llvmlite.build_store(builder, zero, tmp)
self._apply_struct_defaults(pool, builder, mod, struct_ty, class_name, tmp, trans)
# OOP 结构体且有 __init__:调用 __init__ 而非逐字段 store
# 关键字构造调用此前总是逐字段 store,导致 __init__ 方法体不执行
# (如 self._args = mb.alloc(...) 不执行 → self._args 为 NULL → add_argument 崩溃)
has_init_flag: int = 0
has_new_flag: int = 0
if kw_entry is not None:
has_init_flag = kw_entry.HasInit
has_new_flag = kw_entry.HasNew
# 跨模块 OOP 类: HasInit 可能未设置(_translate_oop_methods 未被调用)
# 但 IsOOP=1 说明类有方法,推断 HasInit=1(__init__ 在目标模块中存在)
# 注意: __new__ 是可选的,不推断 HasNew(仅 __init__ 是 OOP 类标准方法)
if is_oop != 0 and has_init_flag == 0:
has_init_flag = 1
if is_oop != 0 and has_init_flag != 0:
# 有 __init__:构建参数数组并调用 __init__
storage_ptr: llvmlite.Value | t.CPtr = tmp
# 如果有 __new__,调用 __new__ 获取实际存储指针
if has_new_flag != 0:
new_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
if new_arg_vals is not None:
string.memset(new_arg_vals, 0, 8 * 32)
new_arg_count: int = 0
for nai in range(can):
new_arg_node: ast.AST | t.CPtr = cargs.get(nai)
if new_arg_node is None:
continue
new_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, new_arg_node, None, 0, trans)
if new_av is not None:
if new_arg_count < 32:
new_arg_vals[new_arg_count] = t.CSizeT(new_av)
new_arg_count += 1
# 关键字参数也传递给 __new__
for nki in range(kw_count):
nkw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(nki))
if nkw is None or nkw.value is None:
continue
nkw_av: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, nkw.value, None, 0, trans)
if nkw_av is not None:
if new_arg_count < 32:
new_arg_vals[new_arg_count] = t.CSizeT(nkw_av)
new_arg_count += 1
new_ptr: llvmlite.Value | t.CPtr = self._call_method_on_ptr(
pool, builder, mod, class_name,
"__new__", tmp, new_arg_vals, new_arg_count, trans)
if new_ptr is not None:
storage_ptr = new_ptr
# __new__ 只保证返回"实例存储指针",声明类型通常是
# `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。
# 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的
# obj.method(如 parser.add_argument)get_class_name_by_type
# 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。
# bitcast 只改类型层视图,运行时零开销(指针位不变)。
if new_ptr.Ty is not None:
nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty):
nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty)
if nw_bc is not None:
storage_ptr = nw_bc
# 构建 __init__ 参数数组:位置参数按顺序 + 关键字参数追加
init_arg_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
if init_arg_vals is not None:
string.memset(init_arg_vals, 0, 8 * 32)
init_arg_count: int = 0
# 位置参数
for ai_init in range(can):
arg_node_init: ast.AST | t.CPtr = cargs.get(ai_init)
if arg_node_init is None:
continue
av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg_node_init, None, 0, trans)
if av_init is not None:
if init_arg_count < 32:
init_arg_vals[init_arg_count] = t.CSizeT(av_init)
init_arg_count += 1
# 关键字参数(追加到末尾,按出现顺序)
for ki_init in range(kw_count):
kw_init: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki_init))
if kw_init is None or kw_init.value is None:
continue
kw_av_init: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, kw_init.value, None, 0, trans)
if kw_av_init is not None:
if init_arg_count < 32:
init_arg_vals[init_arg_count] = t.CSizeT(kw_av_init)
init_arg_count += 1
# 调用 __init__(storage_ptr, *args)
self._call_method_on_ptr(pool, builder, mod, class_name,
"__init__", storage_ptr, init_arg_vals, init_arg_count, trans)
# 返回指针
return storage_ptr
# 无 __init__(或非 OOP):逐字段 store 参数值
# 先处理位置参数(按字段索引,覆盖默认值)
for ai in range(can):
arg: ast.AST | t.CPtr = cargs.get(ai)
if arg is None:
continue
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg, None, 0, trans)
if arg_val is None:
continue
fe: HandlesStruct.FieldEntry | t.CPtr = None
if kw_entry is not None:
fe = HandlesStruct._get_field_entry(kw_entry, ai)
else:
fe = HandlesStruct.get_field_by_index(class_name, ai)
if fe is None:
continue
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, struct_ty, fe.Ty, tmp, fe.Index)
if field_ptr is None:
continue
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, fe.Ty, arg)
llvmlite.build_store(builder, arg_val, field_ptr)
# 处理关键字参数(按字段名查找)
# SHA1 从 kw_entry 获取(规避跨模块同名 find_struct 找错)
kw_sha1: str = None
if kw_entry is not None:
kw_sha1 = kw_entry.ModuleSha1
for ki in range(kw_count):
kw: ast.Keyword | t.CPtr = (ast.Keyword | t.CPtr)(keywords.get(ki))
if kw is None or kw.arg is None or kw.value is None:
continue
fe: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct.lookup_field_by_class(
class_name, kw.arg, kw_sha1)
if fe is None:
continue
kw_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, kw.value, None, 0, trans)
if kw_val is None:
continue
field_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, struct_ty, fe.Ty, tmp, fe.Index)
if field_ptr is None:
continue
kw_val = HandlesExpr.coerce_to_type(builder, kw_val, fe.Ty, kw.value)
llvmlite.build_store(builder, kw_val, field_ptr)
# 返回指针(而非结构体值),赋值时由 coerce_to_type 按目标类型决定是否 load
return tmp
# ============================================================
# _translate_call_with_kwargs — 带关键字参数的函数调用
#
# 支持两种语法:
# 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: t.CChar | t.CPtr = 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 self._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: t.CChar | t.CPtr = 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)
# ============================================================
# _translate_t_type_cast - 翻译 t.XXX(value) 类型转换
#
# 当 func 是 t.XXX 形式且 XXX 是已知类型名(map_t_type 能映射)时,
# 将 value 转换为目标类型:
# - 指针 → 整数: ptrtoint (如 t.CUInt64T(ptr) → i64)
# - 整数 → 指针: inttoptr (如 t.CPtr(int_val) → i8*)
# - 整数 → 整数: trunc/zext (如 t.CInt8T(i32_val) → i8)
# - 指针 → 指针: bitcast (如 t.CPtr(ptr_val) → i8*)
# - 整数 → 浮点: sitofp (如 t.CDouble(i32_val) → double)
# - 浮点 → 整数: fptosi (如 t.CInt(double_val) → i32)
# - 浮点 → 浮点: fpext/fptrunc (如 t.CFloat(double_val) → float)
# ============================================================
def _translate_t_type_cast(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
val: llvmlite.Value | t.CPtr,
target_ty: llvmlite.LLVMType | t.CPtr,
target_name: str = None,
src_node: ast.AST | t.CPtr = None,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""类型转换:根据参数类型和目标类型选择转换方式
整数 → 整数拓宽时(对齐 TPC _HandleTypeCastLlvm L1723-1737):
源 i1(bool)→ zext
目标类型无符号(target_name 命中 CUIntXXT 等)→ zext
源表达式无符号(t.CUIntXXT(x) 强转 / 无符号注解变量)→ zext
否则 → sext(有符号整数拓宽保持数值,如 i8 -50 → 0xFFFFFFCE)
"""
if val is None or target_ty is None:
return None
val_bits: int = HandlesExpr.get_llvm_type_bits(val.Ty)
target_bits: int = HandlesExpr.get_llvm_type_bits(target_ty)
val_fbits: int = HandlesExpr.get_llvm_float_bits(val.Ty)
target_fbits: int = HandlesExpr.get_llvm_float_bits(target_ty)
# 整数 → 整数: trunc/zext/sext
if val_bits != 0 and target_bits != 0:
if val_bits == target_bits:
return val
elif val_bits < target_bits:
if val_bits == 1:
# i1 是布尔值(来自 icmp/fcmp),无符号语义,必须 zext
return llvmlite.build_zext(builder, val, target_ty)
# 目标类型名已知且为有符号 → 按源符号性 sext/zext(对齐 TPC L1723-1737);
# 目标名未知(int()/联合类型强转等)保持默认 zext(旧行为)
need_sext: int = 0
if target_name is not None and HandlesExpr._type_name_unsigned(target_name) == 0:
if src_node is None or HandlesExpr._node_type_unsigned(pool, src_node, trans) == 0:
need_sext = 1
if need_sext != 0:
return llvmlite.build_sext(builder, val, target_ty)
return llvmlite.build_zext(builder, val, target_ty)
else:
return llvmlite.build_trunc(builder, val, target_ty)
# 整数 → 浮点: sitofp
if val_bits != 0 and target_fbits != 0:
return llvmlite.build_si2fp(builder, val, target_ty)
# 浮点 → 整数: fptosi
if val_fbits != 0 and target_bits != 0:
return llvmlite.build_fp2si(builder, val, target_ty)
# 浮点 → 浮点: fpext/fptrunc
if val_fbits != 0 and target_fbits != 0:
if val_fbits == target_fbits:
return val
elif val_fbits < target_fbits:
return llvmlite.build_fpext(builder, val, target_ty)
else:
return llvmlite.build_fptrunc(builder, val, target_ty)
# 指针 → 整数: ptrtoint
if val_bits == 0 and val_fbits == 0 and target_bits != 0:
return llvmlite.build_ptrtoint(builder, val, target_ty)
# 整数 → 指针: inttoptr(必须排除浮点 target,浮点 target_bits 也是 0)
if val_bits != 0 and target_bits == 0 and target_fbits == 0:
return llvmlite.build_inttoptr(builder, val, target_ty)
# 指针 → 指针: bitcast
return llvmlite.build_bitcast(builder, val, target_ty)
# ============================================================
# 泛型实例化辅助:从 Subscript slice 提取类型实参名
# ============================================================
# _get_type_name_from_annotation 已移至 HandlesType.py(支持 BinOp/Attribute)
# HandlesExprCall 通过 HandlesType._get_type_name_from_annotation 调用
def _extract_type_args_from_slice(self, pool: memhub.MemBuddy | t.CPtr,
slice_node: ast.AST | t.CPtr) -> list[str] | t.CPtr:
"""从 Subscript.slice 提取类型实参名列表
list[int] -> ["int"]
dict[str, int] -> ["str", "int"]
list[AST | t.CPtr] -> ["AST|t.CPtr"]
"""
if slice_node is None or pool is None:
return None
# elem_size=8:str 是 i8* 指针(8 字节),若用 4 则双元素时 append 写 8 字节
# 但步长按 4 计算,第 2 个元素覆盖第 1 个元素高 4 字节 → get 读出垃圾指针崩溃
result: list[str] | t.CPtr = list[str](pool, 8)
k: int = slice_node.kind()
if k == ast.ASTKind.Tuple:
tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(slice_node)
elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts
if elts is not None:
n: t.CSizeT = elts.__len__()
i: t.CSizeT
for i in range(n):
elt: ast.AST | t.CPtr = elts.get(i)
tn: str = HandlesType._get_type_name_from_annotation(pool, elt)
if tn is not None:
result.append(tn)
else:
tn: str = HandlesType._get_type_name_from_annotation(pool, slice_node)
if tn is not None:
result.append(tn)
return result
# ============================================================
# 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__
#
# 复用 translate_list_literal 的构造逻辑:
# 1. alloca tmp(特化类临时空间,作为 __new__ 的 self)
# 2. 翻译 cl.args 为参数指针数组
# 3. call __new__(tmp, *args) → storage_ptr
# 4. call __before_init__(storage_ptr)
# 5. call __init__(storage_ptr, *args)
# 6. return storage_ptr
#
# 必须独立于 translate_call 的普通函数路径:spec_name 是类名不是函数名,
# 走裸名路径会被 _lookup_mod_sha1 的 star import 回退误导,用错误的 SHA1
# 且缺少 __new__ 方法名后缀,导致链接报 undefined reference。
# ============================================================
def _infer_generic_ctor_type_arg(self, pool: memhub.MemBuddy | t.CPtr,
arg_node: ast.AST | t.CPtr) -> str:
"""从构造实参 AST 推断泛型类型实参名;无法推断时默认 "int"(与 TPC 一致)
裸名泛型类构造(Box(42) → Box[int])需要从实参推断类型实参。
对应 TPC _HandleGenericClassNewLlvm 的推断逻辑(常量/类型转换调用)。
注意:本函数仅做 AST 静态推断,不发射 IR(避免重复翻译实参)。
"""
if pool is None or arg_node is None:
return "int"
k: int = arg_node.kind()
# 常量: 42→int, 3.14→double, "abc"→str
if k == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg_node)
if cn.const_kind == ast.CONST_FLOAT:
return "double"
if cn.const_kind == ast.CONST_STR:
return "str"
return "int"
# 类型转换调用: int(...)/float(...)/t.CInt(...)/t.CDouble(...)
if k == ast.ASTKind.Call:
cl_f: ast.Call | t.CPtr = (ast.Call | t.CPtr)(arg_node)
if cl_f.func is not None:
if cl_f.func.kind() == ast.ASTKind.Name:
fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_f.func)
if fn_nm.id is not None:
if string.strcmp(fn_nm.id, "float") == 0:
return "double"
if string.strcmp(fn_nm.id, "int") == 0:
return "int"
elif cl_f.func.kind() == ast.ASTKind.Attribute:
fn_at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl_f.func)
if fn_at.attr is not None:
if string.strstr(fn_at.attr, "Float") is not None or string.strstr(fn_at.attr, "Double") is not None:
return "double"
if string.strstr(fn_at.attr, "Int") is not None or string.strstr(fn_at.attr, "UInt") is not None or string.strstr(fn_at.attr, "Char") is not None or string.strstr(fn_at.attr, "Short") is not None or string.strstr(fn_at.attr, "Long") is not None:
return "int"
return "int"
def _translate_generic_ctor_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
spec_name: str,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""泛型类构造调用: list[str](pool, 8) → __new__ + __before_init__ + __init__"""
if pool is None or builder is None or mod is None or spec_name is None or cl is None:
return None
# 查找 struct entry 获取类型
struct_entry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(spec_name)
if struct_entry is None:
HandlesType.fatal_error(cl, "泛型类构造调用: 特化类未注册")
return None
struct_ty: llvmlite.LLVMType | t.CPtr = struct_entry.Ty
if struct_ty is None:
return None
# 确保结构体定义在当前模块中可用(供 alloca 分配空间)
HandlesStruct.ensure_struct_def_in_module(pool, mod, struct_ty)
# alloca tmp(self 指针)
tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, struct_ty)
if tmp is None:
return None
# 翻译 cl.args 为参数指针数组(extra_args[i] = Value 指针)
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
can: t.CSizeT = 0
if cargs is not None:
can = cargs.__len__()
extra_args: t.CSizeT | t.CPtr = pool.alloc(8 * 32)
if extra_args is None:
return None
string.memset(extra_args, 0, 8 * 32)
ai: t.CSizeT = 0
while ai < can:
if ai >= 32:
# 定长 8*32 槽:超过 32 个实参继续写会越界污染 pool 相邻块,fail-fast
HandlesType.fatal_error(
cl, "泛型构造实参超过 32 个上限", "TypeError")
break
arg_node: ast.AST | t.CPtr = cargs.get(ai)
if arg_node is not None:
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg_node, None, 0, trans)
if arg_val is not None:
extra_args[ai] = t.CSizeT(arg_val)
ai += 1
# 存储指针:默认用 alloca,如果有 __new__ 则用 __new__ 返回的指针
# __new__ 是可选的,仅当泛型类模板定义了 __new__ 方法时才调用
# (与 _translate_struct_ctor 保持一致,避免为无 __new__ 的类生成过度声明)
storage_ptr: llvmlite.Value | t.CPtr = tmp
has_new_flag: int = 0
if struct_entry is not None:
has_new_flag = struct_entry.HasNew
if has_new_flag != 0:
new_ptr: llvmlite.Value | t.CPtr = self._call_method_on_ptr(
pool, builder, mod, spec_name, "__new__", tmp, extra_args, can, trans)
if new_ptr is not None:
storage_ptr = new_ptr
# __new__ 只保证返回"实例存储指针",声明类型通常是
# `-> t.CPtr`(i8*),与类的真实类型 Ptr(struct_ty) 不一致。
# 若直接使用,构造结果变量类型退化为 Ptr(i8),无注解变量的
# obj.method(如 parser.add_argument)get_class_name_by_type
# 查不到类名,误报"跨模块调用 'parser.add_argument' 找不到模块 SHA1"。
# bitcast 只改类型层视图,运行时零开销(指针位不变)。
if new_ptr.Ty is not None:
nw_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, struct_ty)
if t.CUInt64T(new_ptr.Ty) != t.CUInt64T(nw_ty):
nw_bc: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, new_ptr, nw_ty)
if nw_bc is not None:
storage_ptr = nw_bc
# call __before_init__(storage_ptr)(TransPyV 自动生成,零值填充)
self._call_method_on_ptr(
pool, builder, mod, spec_name, "__before_init__", storage_ptr, None, 0, trans)
# call __init__(storage_ptr, *args)
self._call_method_on_ptr(
pool, builder, mod, spec_name, "__init__", storage_ptr, extra_args, can, trans)
return storage_ptr
# ============================================================
# 翻译函数调用 Call(func, args) — 模块级版本
# ============================================================
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 = 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 self._translate_super_call(
pool, builder, mod, cl, func_name, trans)
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 = HandlesClassDef._find_generic_template(gen_class_name)
if template_cd is not None:
# 提取类型实参
gen_type_args: list[str] | t.CPtr = self._extract_type_args_from_slice(pool, sub_node.slice)
if gen_type_args is not None and gen_type_args.__len__() > 0:
# 特化泛型类,返回特化类名
spec_name: str = HandlesClassDef._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._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)
HandlesType.fatal_error(gen_nm_node, gt_err)
HandlesType.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 = HandlesType.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 binop_args.__len__() == 1:
binop_arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, binop_args.get(0), funcs_ptr, func_count, trans)
if binop_arg_val is not None:
return self._translate_t_type_cast(pool, builder, binop_arg_val, binop_ty)
return 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 self.translate_c_deref(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "DerefAs") == 0:
return self.translate_c_derefas(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "Addr") == 0:
return self.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 self.translate_c_set(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "Load") == 0:
return self.translate_c_load(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "Asm") == 0:
return self.translate_c_asm(pool, builder, mod, cl, trans)
elif string.strcmp(func_name, "LLVMIR") == 0:
return self.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 cif_args.__len__() >= 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")
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
can: t.CSizeT = 0
if cargs is not None:
can = cargs.__len__()
# ============================================================
# stdarg 糖函数处理: va_arg / arg / va_start / va_end
# 这些函数在 stdarg.vp 中声明为 pass 体,由编译器在翻译期处理:
# va_arg(ap, type) → %N = va_arg <ap_ty> <ap>, <type> (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
# 等价于 (t.CChar | t.CPtr)(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 self._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 self._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
# 检测 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 self._translate_t_type_cast(
pool, builder, tc_arg_val, target_ty,
func_name, tc_arg_node, trans)
# t.XXX 类型转换已确认但不满足参数条件:返回 None,不跌落到跨模块 FATAL
return None
# 裸名 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)
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 self._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
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 = self._extract_type_args_from_slice(pool, sub_sz.slice)
if gen_args_sz is not None and gen_args_sz.__len__() > 0:
gargs_resolved: list[str] | t.CPtr = list[str](pool, 8)
if gargs_resolved is not None:
gai_sz: t.CSizeT = gen_args_sz.__len__()
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]))
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 _:
pass
case llvmlite.LLVMType.Struct(_, _, _):
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")
# 检测 obj.__len__() — 返回 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:
return llvmlite.const_int64(pool, 0)
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() 内置函数调用 — 转换为 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:
# 确保 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_arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(len_val)
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)
# 检测 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 = self._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_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:
st_res: llvmlite.Value | t.CPtr = self._translate_static_class_call(
pool, builder, mod, st_nm.id, func_name, cl, trans)
if st_res is not None:
return st_res
# 检测方法调用: 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:
return self._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:
obj_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, obj_struct_ty, obj_var)
if obj_ptr is not None:
return self._translate_method_call(
pool, builder, mod, inner_nm, func_name,
obj_ptr, cl, trans)
# 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: t.CChar | t.CPtr = 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:
# 结构体已注册:load obj_ptr 走方法调用
i8_ptr_ty2: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
pool, llvmlite.Int8(pool))
obj_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, i8_ptr_ty2, obj_var)
if obj_ptr2 is not None:
return self._translate_method_call(
pool, builder, mod, cls_nm2, func_name,
obj_ptr2, cl, trans)
else:
# 结构体未注册(跨模块依赖未翻译):
# 用模块名查 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:
ret_ty3 = self._fail_method_ret_ty(func_name)
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()
if evk != ast.ASTKind.Name and evk != ast.ASTKind.Attribute:
# 翻译接收者表达式(求值结果应为 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
match expr_obj.Ty:
case llvmlite.LLVMType.Ptr(expr_struct_ty):
expr_cls_nm = HandlesStruct.get_class_name_by_type(
pool, expr_struct_ty)
if expr_cls_nm is not None:
return self._translate_method_call(
pool, builder, mod, expr_cls_nm, func_name,
expr_obj, cl, trans)
# ============================================================
# 检测 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: t.CChar | t.CPtr = 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:
return self._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:
lm_node_kind: int = lm_at.value.kind()
fb_lm: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_lm is not None:
viperlib.snprintf(fb_lm, 1024,
"list 方法 '%s' 的目标对象非指针 (node kind=%d),"
"translate_value 类型推断失败",
lm_name, lm_node_kind)
VLogger.critical(fb_lm, "LIST-METHOD")
return None
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)
# 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:
return llvmlite.build_load(builder, i8_ptr_ty, g_addr)
# 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_ptr: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, s_val_val, i8_ptr_ty, s_val_node)
llvmlite.build_store(builder, s_val_ptr, s_addr)
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:
return llvmlite.build_load(builder, i8_ptr_ty, p_addr)
# 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 not None:
ap_mlen: t.CSizeT = string.strlen(ap_sha1) + 13
ap_mangled: str = pool.alloc(ap_mlen)
if ap_mangled is not None:
viperlib.snprintf(ap_mangled, ap_mlen, "%s.list.append", ap_sha1)
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)
# 获取关键字参数
keywords: list[ast.AST | t.CPtr] | t.CPtr = cl.keywords
kw_count: t.CSizeT = 0
if keywords is not None:
kw_count = keywords.__len__()
# 检查是否是结构体构造函数: 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: HandlesStruct.StructEntry | t.CPtr = None
vis: int = HandlesStruct.is_struct_visible(func_name)
if vis != 0:
if trans is not None:
gen_ctor_entry = HandlesStruct.find_struct_by_module(func_name, trans.ModuleSha1)
if gen_ctor_entry is None:
gen_ctor_entry = HandlesStruct.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 = HandlesImports.is_module_imported(trans._imported_modules, mod_nm_qc.id)
if imp_ok != 0:
if trans is not None:
gen_ctor_entry = HandlesStruct.find_struct_by_module(func_name, trans.ModuleSha1)
if gen_ctor_entry is None:
gen_ctor_entry = HandlesStruct.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 = HandlesImports.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 = HandlesStruct.find_struct_by_module(co_buf, ctor_sha1)
if gen_ctor_entry is None:
gen_ctor_entry = HandlesStruct.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._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._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: HandlesStruct.FieldEntry | t.CPtr = HandlesStruct._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 = HandlesStruct.struct_has_defaults(func_name)
if gen_has_defaults == 1:
# 有默认值:走构造函数路径应用默认值
return self._translate_struct_ctor(
pool, builder, mod, struct_ty, func_name, cargs, 0, trans)
# 无默认值:返回 zeroinitializer
ret: llvmlite.Value | t.CPtr = llvmlite.ConstZero(pool, struct_ty)
return ret
if kw_count > 0:
# 有关键字参数:按字段名赋值
return self._translate_struct_ctor_kw(
pool, builder, mod, struct_ty, func_name, cargs, can,
keywords, kw_count, trans)
# 仅位置参数:按字段顺序构建
return self._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 分支,此处处理裸名 + 推断。)
if struct_ty is None and gen_ctor_entry is None and trans is not None:
if cl.func is not None and cl.func.kind() == ast.ASTKind.Name:
template_cd_bare: ast.ClassDef | t.CPtr = HandlesClassDef._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 = tp_bare.__len__()
if tp_count_bare > 0:
inferred_args_bare: list[str] | t.CPtr = list[str](pool, 8)
if inferred_args_bare is not None:
tpi_bare: t.CSizeT = 0
for tpi_bare in range(tp_count_bare):
ta_bare: str = "int"
if tpi_bare < can:
ta_bare = self._infer_generic_ctor_type_arg(pool, cargs.get(tpi_bare))
inferred_args_bare.append(ta_bare)
spec_name_bare: str = HandlesClassDef._specialize_generic_class(
trans, func_name, inferred_args_bare)
if spec_name_bare is not None:
return self._translate_generic_ctor_call(
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 HandlesClassDef._is_renum_class_name(rc_cls_name) != 0:
# 在该 REnum 类中查找变体名 func_name
rc_tag: int = HandlesClassDef._lookup_renum_variant_in_class(
rc_cls_name, func_name)
if rc_tag >= 0:
return self._translate_renum_construct(
pool, builder, mod, rc_cls_name, func_name,
rc_tag, cargs, can, trans)
# 查找函数:优先从函数表按裸名精确匹配(同模块函数),
# 再从模块函数链表按后缀匹配(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: HandlesExprCall.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:
# 裸名调用:允许精确 + 后缀匹配
found_func = self.find_func_in_module(mod, func_name)
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:
ff_name: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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 HandlesStruct.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._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.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:
call_ret_ty = self._infer_external_func_ret_ty(pool, func_name)
# 如果模块中找不到函数,检查是否是变量(函数指针 / 闭包调用)
if found_func is None:
fp_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, func_name)
if fp_alloca is not None:
# 闭包变量(嵌套函数提升,已注册到闭包名集合):提取 fn_ptr/env_ptr 间接调用
if HandlesExprCall.is_closure_name(func_name) != 0:
return HandlesExprCall.translate_closure_call(pool, builder, mod, fp_alloca,
cargs, can)
# 函数指针变量(t.Callable 注解 → i8** alloca):按实参构造签名间接调用
if HandlesExprCall._is_func_ptr_alloca(fp_alloca) != 0:
return HandlesExprCall._translate_func_ptr_call(pool, builder, mod, fp_alloca,
func_name, cargs, can, trans)
# 其他 i8* 变量按闭包调用路径处理
return HandlesExprCall.translate_closure_call(pool, builder, mod, fp_alloca,
cargs, can)
# 翻译参数并链接
# 有关键字参数且找到函数定义时,按参数名匹配
if kw_count > 0 and found_func is not None and found_params is not None:
return self._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 = HandlesExpr.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:
ext_param_ty: llvmlite.LLVMType | t.CPtr = self._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)
tgt_bits_ap: int = HandlesExpr.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 = HandlesExpr.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 = HandlesExpr.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 = HandlesExpr.get_llvm_type_bits(arg_val.Ty)
af_va: int = HandlesExpr.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: FuncEntry | t.CPtr = HandlesExprCall.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
# 如果当前模块没有,从全局默认参数表查找(跨模块)
if df_defaults is None:
gd_entry: FuncDefaultsEntry | t.CPtr = HandlesExprCall.find_func_defaults(func_name)
if 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 = HandlesExprCall._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 = HandlesExpr.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: t.CChar | t.CPtr = 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:
xmod_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(xmod_at.value)
if xmod_nm.id is not None:
mod_sha1: str = self._lookup_module_sha1(xmod_nm.id)
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 = HandlesImports.is_module_imported(
trans._imported_modules, xmod_nm.id)
if is_xmod_imported == 0:
err_ni: t.CChar | t.CPtr = pool.alloc(256)
if err_ni is not None:
viperlib.snprintf(err_ni, 256,
"跨模块调用 '%s.%s':模块 '%s' 未导入(请先 import %s)",
xmod_nm.id, func_name, xmod_nm.id, xmod_nm.id)
HandlesType.fatal_error(xmod_nm, err_ni)
HandlesType.fatal_error(xmod_nm, "跨模块调用:模块未导入")
# 检查是否是 re-export 函数(如 ast._lexer_init 实际定义在 ast.lexer)
reexport_src: str = HandlesImports.lookup_reexport(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.is_cexport_func(mod_sha1, func_name) != 0:
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_nm.id, "t") == 0 or string.strcmp(xmod_nm.id, "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 = HandlesImports.is_module_imported(
trans._imported_modules, xmod_nm.id)
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_nm.id, 0)
if alias_sha1 is not None:
if self.is_cexport_func(alias_sha1, func_name) != 0:
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: t.CChar | t.CPtr = pool.alloc(256)
if err_msg_imp is not None:
viperlib.snprintf(err_msg_imp, 256, "模块 '%s' 已导入但 SHA1 未注册(该模块未被编译)", xmod_nm.id)
HandlesType.fatal_error(xmod_nm, err_msg_imp)
HandlesType.fatal_error(xmod_nm, "已导入模块 SHA1 未注册")
else:
# 检查是否是通过 from import 导入的名称(如 from .__types import LLVMType)
# LLVMType.Ptr(ty) 中 LLVMType 是类名不是模块名,
# 但 Ptr 是 __types 模块的模块级函数
# 禁用 star import 回退:xmod_nm.id 是明确名称,不应回退到 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_nm.id, 0)
if from_sha1 is not None:
# CExport 函数定义用裸名,跨模块调用需用裸名
if self.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: t.CChar | t.CPtr = pool.alloc(256)
if err_msg2 is not None:
viperlib.snprintf(err_msg2, 256, "跨模块调用 '%s.%s' 找不到模块 SHA1", xmod_nm.id, func_name)
HandlesType.fatal_error(xmod_nm, err_msg2)
HandlesType.fatal_error(xmod_nm, "跨模块调用找不到模块 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 = HandlesImports.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
if self.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: t.CChar | t.CPtr = pool.alloc(256)
if err_msg3 is not None:
viperlib.snprintf(err_msg3, 256, "裸名调用 '%s' 未定义且未导入", func_name)
HandlesType.fatal_error(node, err_msg3)
HandlesType.fatal_error(node, "裸名调用未定义且未导入")
else:
err_msg4: t.CChar | t.CPtr = pool.alloc(256)
if err_msg4 is not None:
viperlib.snprintf(err_msg4, 256, "裸名调用 '%s' 未定义且未导入", func_name)
HandlesType.fatal_error(node, err_msg4)
HandlesType.fatal_error(node, "裸名调用未定义且未导入")
# 直接调用
# 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)
# 别名导入重新推断返回类型:
# 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)
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._is_sha1_mangled_call(call_name) != 0:
if trans is None or trans._declare_only == 0:
cf_dot: t.CChar | t.CPtr = string.strchr(call_name, '.')
cf_last: t.CChar | t.CPtr = string.strrchr(call_name, '.')
if cf_dot is not None and cf_last is not None:
cf_sha1: t.CChar | t.CPtr = 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: t.CChar | t.CPtr = 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)
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: t.CChar | t.CPtr = 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")
HandlesType.fatal_error(
node,
f"跨模块函数返回类型无法精确获取(text.ll/vpi 均未命中),默认 i32 会截断指针: {call_name}",
"TypeError")
else:
if trans is not None:
trans._deps_pending = 1
cf_dbg: t.CChar | t.CPtr = VLogger.fmt_buf()
if cf_dbg is not None:
viperlib.snprintf(
cf_dbg, 1024,
"跨模块函数 '%s' 依赖模块 text.ll 尚未生成(Phase A 顺序),"
"标记重试,本遍保持默认类型", call_name)
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 提升
is_variadic_call: int = HandlesExprCall._check_and_promote_variadic_call(pool, builder, mod, call_name, head, can)
return llvmlite.build_call(builder, call_name, head, can, call_ret_ty, is_variadic_call)
# ============================================================
# isinstance - 运行时 vtable 子类集合比较(2026-08-10)
#
# CVTable 对象头部 vtable 指针唯一标识对象实际类。isinstance(obj, Cls)
# 语义 = Cls 是实际类的祖先(实际类 == Cls 或继承自 Cls)。运行时只能
# 拿到实际类 vtable 地址,无法向上推导祖先链,因此在编译期沿
# StructEntry.ParentNames 反向 BFS 枚举 Cls 的全部已知子类(含自身),
# 运行时比较 obj->vtable ∈ {Cls 子类 vtable 地址集合}。
# NoVTable / 未知类回退编译时静态判断(obj 静态类型 MRO 判断)。
# ============================================================
# isinstance 子类收集上限(防数组越界;t.CDefine 注解由 TPC 解析为 i32)
ISINSTANCE_CLASS_MAX: t.CDefine = 64
def _translate_isinstance(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
obj_node: ast.AST | t.CPtr,
cls_node: ast.AST | t.CPtr,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""isinstance(obj, Cls):运行时 vtable 子类集合比较,返回 i1"""
if obj_node is None or cls_node is None:
return llvmlite.const_int(pool, 1, 0)
dbg_enter: t.CChar | t.CPtr = VLogger.fmt_buf()
if dbg_enter is not None:
viperlib.snprintf(dbg_enter, 1024, "[ISINSTANCE] ENTER kind=%d", cls_node.kind())
VLogger.info(dbg_enter, "ISINSTANCE")
obj_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, obj_node, None, 0, trans)
dbg_a: t.CChar | t.CPtr = VLogger.fmt_buf()
if dbg_a is not None:
viperlib.snprintf(dbg_a, 1024, "[ISINSTANCE] A obj_set=%d",
0 if obj_val is None else 1)
VLogger.info(dbg_a, "ISINSTANCE")
if obj_val is None or obj_val.Ty is None:
return llvmlite.const_int(pool, 1, 0)
# 对象指针规整:二级指针(变量 alloca / 联合 Class|t.CPtr)先 load
obj_ptr: llvmlite.Value | t.CPtr = obj_val
match obj_val.Ty:
case llvmlite.LLVMType.Ptr(inner_ty):
match inner_ty:
case llvmlite.LLVMType.Ptr(_):
loaded: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, inner_ty, obj_val)
if loaded is not None:
obj_ptr = loaded
case _:
pass
obj_is_ptr: int = HandlesExpr.is_ptr_type(obj_ptr.Ty)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
i8_ptr_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ptr_ty)
# 对象 vtable 指针惰性读取(首个 CVTable 类比较时执行一次)
vtable_ptr: llvmlite.Value | t.CPtr = None
vtable_ready: int = 0
res: llvmlite.Value | t.CPtr = None
cls_names: t.CSizeT | t.CPtr = self._extract_isinstance_class_names(pool, cls_node)
dbg_b: t.CChar | t.CPtr = VLogger.fmt_buf()
if dbg_b is not None:
viperlib.snprintf(dbg_b, 1024, "[ISINSTANCE] B cls_names=%d cls0=%lld",
0 if cls_names is None else 1,
cls_names[0] if cls_names is not None else -1)
VLogger.info(dbg_b, "ISINSTANCE")
if cls_names is None:
return llvmlite.const_int(pool, 1, 0)
dbg0: t.CChar | t.CPtr = VLogger.fmt_buf()
if dbg0 is not None:
viperlib.snprintf(dbg0, 1024, "[ISINSTANCE] C kind=%d ptr=%d cls0=%lld",
cls_node.kind(), obj_is_ptr, cls_names[0])
VLogger.info(dbg0, "ISINSTANCE")
ci: int = 0
while cls_names[ci] != 0:
cn: str = (str | t.CPtr)(t.CVoid(cls_names[ci], t.CPtr))
if cn is not None:
dbg1: t.CChar | t.CPtr = VLogger.fmt_buf()
if dbg1 is not None:
viperlib.snprintf(dbg1, 1024, "[ISINSTANCE] cn_ptr=%lld nv=%d vt=%d",
cls_names[ci],
HandlesStruct.is_novtable_by_name(cn),
HandlesStruct.has_vtable_by_name(cn))
VLogger.info(dbg1, "ISINSTANCE")
if HandlesStruct.is_novtable_by_name(cn) != 0 \
or HandlesStruct.has_vtable_by_name(cn) == 0:
# NoVTable / 未知类 → 编译时静态判断(obj 静态类型 MRO)
st: int = self._isinstance_compile_time(pool, obj_ptr, cn)
c1: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 1, 1 if st > 0 else 0)
if res is None:
res = c1
else:
res = llvmlite.build_or(builder, res, c1)
elif obj_is_ptr != 0:
# CVTable → 运行时 vtable 比较(读对象头部 vtable 指针)
if vtable_ready == 0:
vtable_slot: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(
builder, obj_ptr, i8_ptr_ptr_ty)
if vtable_slot is not None:
vtable_ptr = llvmlite.build_load(builder, i8_ptr_ty, vtable_slot)
vtable_ready = 1
if vtable_ptr is not None:
subs: t.CSizeT | t.CPtr = self._collect_subclass_vtable_classes(pool, cn)
dbg2: t.CChar | t.CPtr = VLogger.fmt_buf()
if dbg2 is not None:
viperlib.snprintf(dbg2, 1024, "[ISINSTANCE] cn_ptr=%lld subs0=%lld subs1=%lld",
cls_names[ci],
subs[0] if subs is not None else -1,
subs[1] if subs is not None else -1)
VLogger.info(dbg2, "ISINSTANCE")
if subs is not None:
k: int = 0
while subs[k] != 0:
scn: str = (str | t.CPtr)(t.CVoid(subs[k], t.CPtr))
if scn is not None:
sub_i8: llvmlite.Value | t.CPtr = self._make_vtable_ref_i8(
pool, builder, mod, scn, trans)
if sub_i8 is not None:
cmp: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, llvmlite.ICMP_EQ, vtable_ptr, sub_i8)
if cmp is not None:
if res is None:
res = cmp
else:
res = llvmlite.build_or(builder, res, cmp)
else:
dbg_ci: t.CChar | t.CPtr = VLogger.fmt_buf()
if dbg_ci is not None:
viperlib.snprintf(dbg_ci, 1024, "[ISINSTANCE] CMP-NONE subs_k=%lld", subs[k])
VLogger.info(dbg_ci, "ISINSTANCE")
else:
dbg_ri: t.CChar | t.CPtr = VLogger.fmt_buf()
if dbg_ri is not None:
viperlib.snprintf(dbg_ri, 1024, "[ISINSTANCE] REF-NONE subs_k=%lld", subs[k])
VLogger.info(dbg_ri, "ISINSTANCE")
k += 1
else:
dbg_sn: t.CChar | t.CPtr = VLogger.fmt_buf()
if dbg_sn is not None:
viperlib.snprintf(dbg_sn, 1024, "[ISINSTANCE] SUBS-NONE cn=%lld", cls_names[ci])
VLogger.info(dbg_sn, "ISINSTANCE")
ci += 1
if res is None:
dbg_rn: t.CChar | t.CPtr = VLogger.fmt_buf()
if dbg_rn is not None:
viperlib.snprintf(dbg_rn, 1024, "[ISINSTANCE] RES-NONE")
VLogger.info(dbg_rn, "ISINSTANCE")
return llvmlite.const_int(pool, 1, 0)
return res
def _extract_isinstance_class_names(self, pool: memhub.MemBuddy | t.CPtr,
node: ast.AST | t.CPtr) -> t.CSizeT | t.CPtr:
"""从 isinstance 第二参数提取类名数组(Name→id / Attribute→attr / Tuple→遍历)"""
arr: t.CSizeT | t.CPtr = pool.alloc(8 * 16)
if arr is None:
return None
# 全数组清零:pool 分配内存非零时,未初始化槽位会被 while cls_names[ci]!=0
# 误当类名指针解引用 → 段错误
string.memset(arr, 0, 8 * 16)
arr[0] = 0
if node is None:
return arr
count: int = 0
k: int = node.kind()
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
if nm.id is not None:
arr[0] = t.CSizeT(nm.id)
elif k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
if at.attr is not None:
arr[0] = t.CSizeT(at.attr)
elif k == ast.ASTKind.Tuple:
tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(node)
elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts
if elts is not None:
n: t.CSizeT = elts.__len__()
for i in range(n):
if count >= 15:
break
elt: ast.AST | t.CPtr = elts.get(i)
if elt is None:
continue
ek: int = elt.kind()
if ek == ast.ASTKind.Name:
enm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(elt)
if enm.id is not None:
arr[count] = t.CSizeT(enm.id)
count += 1
elif ek == ast.ASTKind.Attribute:
eat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(elt)
if eat.attr is not None:
arr[count] = t.CSizeT(eat.attr)
count += 1
arr[count] = 0
return arr
def _collect_subclass_vtable_classes(self, pool: memhub.MemBuddy | t.CPtr,
class_name: str) -> t.CSizeT | t.CPtr:
"""反向 BFS 收集目标类及全部子类(含自身,仅 HasVTable==1),返回 0 结尾数组"""
if class_name is None:
return None
names: t.CSizeT | t.CPtr = pool.alloc(8 * (ISINSTANCE_CLASS_MAX + 1))
queue: t.CSizeT | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX)
visited: t.CSizeT | t.CPtr = pool.alloc(8 * ISINSTANCE_CLASS_MAX)
if names is None or queue is None or visited is None:
return None
string.memset(names, 0, 8 * (ISINSTANCE_CLASS_MAX + 1))
string.memset(queue, 0, 8 * ISINSTANCE_CLASS_MAX)
string.memset(visited, 0, 8 * ISINSTANCE_CLASS_MAX)
qcount: int = 0
outcount: int = 0
vcount: int = 0
queue[0] = t.CSizeT(class_name)
qcount = 1
while qcount > 0:
qcount -= 1
cur_addr: t.CSizeT = queue[qcount]
cur: str = (str | t.CPtr)(t.CVoid(cur_addr, t.CPtr))
if cur is None:
continue
dup: int = 0
for vi in range(vcount):
va: t.CSizeT = visited[vi]
if va != 0:
vn: str = (str | t.CPtr)(t.CVoid(va, t.CPtr))
if vn is not None and string.strcmp(vn, cur) == 0:
dup = 1
break
if dup != 0:
continue
if vcount < ISINSTANCE_CLASS_MAX:
visited[vcount] = t.CSizeT(cur)
vcount += 1
centry: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(cur)
if centry is not None and centry.HasVTable != 0:
if outcount < ISINSTANCE_CLASS_MAX:
names[outcount] = t.CSizeT(cur)
outcount += 1
# 子类入队:遍历全部已注册 struct,ParentNames 含 cur 者
scnt: int = HandlesStruct.get_struct_count()
for i in range(scnt):
e2: HandlesStruct.StructEntry | t.CPtr = HandlesStruct._get_struct_entry(i)
if e2 is None or e2.Name is None:
continue
if e2.ParentCount > 0 and e2.ParentNames is not None:
parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(e2.ParentNames, t.CPtr))
for j in range(e2.ParentCount):
pa: t.CSizeT = parr[j]
if pa != 0:
pn: str = (str | t.CPtr)(t.CVoid(pa, t.CPtr))
if pn is not None and string.strcmp(pn, cur) == 0:
if qcount < ISINSTANCE_CLASS_MAX:
queue[qcount] = t.CSizeT(e2.Name)
qcount += 1
break
names[outcount] = 0
return names
def _make_vtable_ref_i8(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str,
trans: HT.Translator | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""构造类 vtable 地址引用(i8*):本模块已定义直接引用,跨模块声明 external"""
if class_name is None:
return None
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
buf: t.CChar | t.CPtr = pool.alloc(256)
if buf is None:
return None
viperlib.snprintf(buf, 256, "%s.vtable", class_name)
vn: str = (str | t.CPtr)(buf)
sha1: str = HandlesStruct.get_struct_sha1(class_name)
if sha1 is None:
if trans is None:
return None
sha1 = trans.ModuleSha1
if sha1 is None:
return None
mangled: str = HandlesFunctions._mangle_name_with_sha1(sha1, vn)
ref_name: t.CChar | t.CPtr = pool.alloc(256)
if ref_name is None:
return None
# vtable 名含 sha1 点号前缀,一律 @"..." 引号形式
viperlib.snprintf(ref_name, 256, "@\"%s\"", mangled)
gv: llvmlite.GlobalVariable | t.CPtr = HandlesExpr.find_global_in_module(mod, mangled)
ref_ty: llvmlite.LLVMType | t.CPtr = None
if gv is not None:
# 本模块已定义 vtable(constant {i8* x N})→ 引用类型 Ptr(struct)
ref_ty = llvmlite.Ptr(pool, gv.Ty)
else:
# 跨模块:声明 @mangled = external global i8*,引用类型 i8**
gv2: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(
pool, mangled, i8_ptr_ty)
if gv2 is None:
return None
llvmlite.module_add_global(mod, gv2)
ref_ty = llvmlite.Ptr(pool, i8_ptr_ty)
ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, ref_ty, ref_name)
if ref is None:
return None
return llvmlite.build_bitcast(builder, ref, i8_ptr_ty)
def _isinstance_compile_time(self, pool: memhub.MemBuddy | t.CPtr,
obj_ptr: llvmlite.Value | t.CPtr,
class_name: str) -> int:
"""编译时静态判断:obj 静态类型 == class_name 或 class_name 在其 MRO 中"""
if obj_ptr is None or obj_ptr.Ty is None or class_name is None:
return 0
match obj_ptr.Ty:
case llvmlite.LLVMType.Ptr(obj_struct_ty):
sname: str = HandlesStruct.get_class_name_by_type(pool, obj_struct_ty)
if sname is not None:
if string.strcmp(sname, class_name) == 0:
return 1
mro: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, sname)
if mro is not None:
k: int = 0
while mro[k] != 0:
mn: str = (str | t.CPtr)(t.CVoid(mro[k], t.CPtr))
if mn is not None and string.strcmp(mn, class_name) == 0:
return 1
k += 1
case _:
pass
return 0
# ============================================================
# P4 簇 5+6 迁移方法(函数体来自 HandlesExprCall.vp:
# 闭包调用/函数指针/printf/print/stdarg 糖/变长参数提升/函数表/全局注册表)
# 本模块函数调用改 self.,外部模块调用保留模块前缀,全局变量改 self 字段
# ============================================================
def translate_closure_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
closure_alloca: llvmlite.Value | t.CPtr,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT) -> llvmlite.Value | t.CPtr:
"""通过闭包指针间接调用"""
if builder is None or closure_alloca is None:
return None
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 1. 加载闭包指针 (i8*)
closure_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, closure_alloca)
if closure_ptr is None:
return None
# 2. 加载 fn_ptr (offset 0): bitcast to i8**, load i8*
fn_ptr_addr: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, closure_ptr, llvmlite.Ptr(pool, i8_ptr_ty))
if fn_ptr_addr is None:
return None
fn_raw: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fn_ptr_addr)
if fn_raw is None:
return None
# 3. 加载 env_ptr (offset 8): GEP i8, closure, 8; load i8*
eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 8)
env_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, closure_ptr, eight_val)
if env_addr is None:
return None
env_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, env_addr)
if env_ptr is None:
return None
# 4. bitcast fn_raw to i32 (i8*)*
param_node: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, i8_ptr_ty)
func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, i32_ty, param_node, 1)
func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty)
fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_raw, func_ptr_ty)
if fn_typed is None:
return None
# 5. 间接调用: call i32 %fn_typed(i8* %env_ptr)
env_ptr.Next = None
return llvmlite.build_call_indirect(builder, fn_typed, env_ptr, 1, i32_ty)
def _is_func_ptr_alloca(self, alloca: llvmlite.Value | t.CPtr) -> int:
"""判断 alloca 是否为函数指针变量(类型 Ptr(Ptr(i8))),1=是 / 0=否"""
if alloca is None or alloca.Ty is None:
return 0
if HandlesExpr.is_ptr_type(alloca.Ty) == 0:
return 0
pointee: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
if pointee is None or HandlesExpr.is_ptr_type(pointee) == 0:
return 0
inner: llvmlite.LLVMType | t.CPtr = pointee.Pointee
if inner is None or HandlesExpr.is_ptr_type(inner) != 0:
return 0
return 1
def _ensure_closure_names(self) -> int:
"""确保闭包名表已分配,0 失败"""
if self.ClosureNames is not None:
return 1
self.ClosureNames = stdlib.malloc(64 * MAX_CLOSURE_NAMES)
if self.ClosureNames is None:
return 0
string.memset(self.ClosureNames, 0, 64 * MAX_CLOSURE_NAMES)
return 1
def register_closure_name(self, name: str) -> int:
"""注册嵌套函数(闭包变量)名,0 成功"""
if name is None:
return 1
if self._ensure_closure_names() == 0:
return 1
if self.ClosureCount >= MAX_CLOSURE_NAMES:
return 1
idx: t.CSizeT = t.CSizeT(self.ClosureCount) * 64
string.strncpy(self.ClosureNames + idx, name, 63)
self.ClosureCount += 1
return 0
def is_closure_name(self, name: str) -> int:
"""检查 name 是否已注册为闭包变量名,1=是 / 0=否"""
if name is None or self.ClosureNames is None:
return 0
i: t.CSizeT
for i in range(self.ClosureCount):
if string.strcmp(self.ClosureNames + i * 64, name) == 0:
return 1
return 0
def _ensure_funcptr_sigs(self) -> int:
"""确保函数指针签名表已分配(stdlib.malloc,懒初始化)"""
if self.FuncptrNames is not None:
return 1
self.FuncptrNames = stdlib.malloc(64 * MAX_FUNC_PTR_SIGS)
self.FuncptrRets = stdlib.malloc(8 * MAX_FUNC_PTR_SIGS)
if self.FuncptrNames is None or self.FuncptrRets is None:
return 0
string.memset(self.FuncptrNames, 0, 64 * MAX_FUNC_PTR_SIGS)
return 1
def register_func_ptr_sig(self, name: str,
ret_ty: llvmlite.LLVMType | t.CPtr) -> int:
"""注册函数指针变量的返回类型签名,0 成功"""
if name is None or ret_ty is None:
return 1
if self._ensure_funcptr_sigs() == 0:
return 1
if self.FuncptrCount >= MAX_FUNC_PTR_SIGS:
return 1
idx: t.CSizeT = t.CSizeT(self.FuncptrCount) * 64
# 槽位定长 64 字节,与 register_closure_name 一致用 strncpy 钳制防越界
string.strncpy(self.FuncptrNames + idx, name, 63)
self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_ty)
self.FuncptrCount += 1
return 0
def lookup_func_ptr_ret(self, name: str) -> llvmlite.LLVMType | t.CPtr:
"""查函数指针变量的返回类型,None=未注册(调用时默认 i32)"""
if name is None or self.FuncptrNames is None:
return None
for i in range(self.FuncptrCount):
idx: t.CSizeT = t.CSizeT(i) * 64
if string.strcmp(self.FuncptrNames + idx, name) == 0:
return (llvmlite.LLVMType | t.CPtr)(
t.CVoid(self.FuncptrRets[i], t.CPtr))
return None
def _translate_func_ptr_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
fp_alloca: llvmlite.Value | t.CPtr,
func_name: str,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""函数指针变量间接调用,返回结果 Value"""
if builder is None or fp_alloca is None:
return None
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 1. load 函数地址 (i8*)
fn_i8: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, fp_alloca)
if fn_i8 is None:
return None
# 2. 翻译实参并链接为 Value 链表
head: llvmlite.Value | t.CPtr = None
tail: llvmlite.Value | t.CPtr = None
arg_count: int = 0
ai: t.CSizeT
for ai in range(can):
arg: ast.AST | t.CPtr = cargs.get(ai)
if arg is not None:
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg, None, 0, trans)
if arg_val is not None:
arg_val.Next = None
if head is None:
head = arg_val
else:
tail.Next = arg_val
tail = arg_val
arg_count += 1
# 3. 按实参类型 + 注册的返回类型构造签名(未注册返回类型时默认 i32)
ret_ty: llvmlite.LLVMType | t.CPtr = self.lookup_func_ptr_ret(func_name)
if ret_ty is None:
ret_ty = i32_ty
fp_first: llvmlite.ParamNode | t.CPtr = None
fp_prev: llvmlite.ParamNode | t.CPtr = None
cur_v: llvmlite.Value | t.CPtr = head
for pi in range(arg_count):
if cur_v is None:
break
cur_ty: llvmlite.LLVMType | t.CPtr = llvmlite.value_get_ty(cur_v)
pn2: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, cur_ty)
if pn2 is not None:
if fp_first is None:
fp_first = pn2
if fp_prev is not None:
llvmlite.paramnode_set_next(fp_prev, pn2)
fp_prev = pn2
cur_v = llvmlite.value_get_next(cur_v)
func_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func(pool, ret_ty, fp_first, arg_count)
if func_ty is None:
return None
func_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, func_ty)
# 4. bitcast i8* → 函数指针类型,间接调用
fn_typed: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, fn_i8, func_ptr_ty)
if fn_typed is None:
return None
return llvmlite.build_call_indirect(builder, fn_typed, head, arg_count, ret_ty)
def translate_printf_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None):
"""翻译 printf 调用(特殊处理格式字符串)"""
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None:
return
can: t.CSizeT = cargs.__len__()
if can == 0:
return
arg0: ast.AST | t.CPtr = cargs.get(0)
if arg0 is None:
return
fmt_str: str = None
arg0_kind: int = arg0.kind()
if arg0_kind == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(arg0)
if cn.const_kind == ast.CONST_STR:
fmt_str = cn.str_val
if fmt_str is None:
return
fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string(
builder, pool, mod, fmt_str, trans)
if fmt_ptr is None:
return
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 翻译额外参数并链接
prev: llvmlite.Value | t.CPtr = fmt_ptr
for ai in range(1, can):
arg: ast.AST | t.CPtr = cargs.get(ai)
if arg is not None:
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg, None, 0, trans)
if arg_val is not None:
# C ABI integer promotion: i8/i16 → i32(printf 变参函数要求)
arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty)
if arg_bits != 0 and arg_bits < 32:
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, i32_ty, arg)
# C ABI float promotion: float → double(printf 变参函数要求)
arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty)
if arg_fbits != 0 and arg_fbits < 64:
double_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
arg_val = HandlesExpr.coerce_to_type(builder, arg_val, double_ty, arg)
arg_val.Next = None
prev.Next = arg_val
prev = arg_val
prev.Next = None
# is_variadic=1: 生成带显式函数类型签名的 call(如 call i32 (i8*, ...) @printf),
# 让 llc 识别为 variadic 调用,生成正确的 Win64 ABI 代码(浮点参数同时传 XMM 和整数寄存器)
llvmlite.build_call(builder, "printf", fmt_ptr, can, i32_ty, 1)
def translate_print_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
trans: HT.Translator | t.CPtr = None):
"""翻译 print 调用(类型感知格式化 + 默认换行)"""
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None:
return
FMT_BUF_SIZE: t.CSizeT = 256
fmt_buf: bytes = stdlib.malloc(FMT_BUF_SIZE)
if fmt_buf is None:
return
fmt_buf[0] = '\0'
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
dbl_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
can: t.CSizeT = cargs.__len__()
arg_head: llvmlite.Value | t.CPtr = None
arg_tail: llvmlite.Value | t.CPtr = None
arg_count: int = 1 # 格式串本身是第 1 个 printf 参数
for ai in range(can):
arg: ast.AST | t.CPtr = cargs.get(ai)
if arg is None:
continue
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, arg, None, 0, trans)
if arg_val is None or arg_val.Ty is None:
# 参数翻译失败 → "(null)"(与 TPC 一致,不传参)
if string.strlen(fmt_buf) < FMT_BUF_SIZE - 16:
viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 16, "(null)")
continue
# 数组名(如 print(l),l: t.CArray[t.CChar, N]):
# translate_value 会 load 出数组值([N x T]),print 无法格式化;
# 按数组退化语义取数组 alloca 地址——字符数组 → %s(打印字符串内容),
# 其他元素类型 → 0x%llx(打印数组地址)。
array_ptr: llvmlite.Value | t.CPtr = None
array_elem_bits: int = 0
if arg.kind() == ast.ASTKind.Name and trans is not None:
anm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg)
if anm.id is not None:
arr_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, anm.id)
if arr_alloca is not None and arr_alloca.Ty is not None \
and HandlesExpr.is_ptr_type(arr_alloca.Ty) != 0:
arr_pointee: llvmlite.LLVMType | t.CPtr = arr_alloca.Ty.Pointee
if arr_pointee is not None:
match arr_pointee:
case llvmlite.LLVMType.Array(arr_et, arr_n):
array_ptr = arr_alloca
array_elem_bits = HandlesExpr.get_llvm_type_bits(arr_et)
case _:
pass
token: t.CChar | t.CPtr = None
chain_arg: int = 1 # 1=该 token 消耗一个参数,0=纯文本
arg_bits: int = HandlesExpr.get_llvm_type_bits(arg_val.Ty)
arg_fbits: int = HandlesExpr.get_llvm_float_bits(arg_val.Ty)
if array_ptr is not None:
# 数组退化:字符数组 → %s(bitcast [N x i8]* 到 i8*);其他 → 0x%llx
if array_elem_bits == 8:
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(
pool, llvmlite.Int8(pool))
token = "%s"
arg_val = llvmlite.build_bitcast(builder, array_ptr, i8_ptr_ty)
else:
token = "0x%llx"
arg_val = llvmlite.build_ptrtoint(builder, array_ptr, i64_ty)
elif HandlesExpr.is_ptr_type(arg_val.Ty) != 0:
# i8*(str/bytes)→ %s;其他指针 → 0x%llx
pointee: llvmlite.LLVMType | t.CPtr = arg_val.Ty.Pointee
if pointee is not None and HandlesExpr.get_llvm_type_bits(pointee) == 8:
token = "%s"
else:
token = "0x%llx"
arg_val = llvmlite.build_ptrtoint(builder, arg_val, i64_ty)
elif arg_bits != 0:
if arg_bits == 1:
token = "%d"
arg_val = llvmlite.build_zext(builder, arg_val, i32_ty)
elif arg_bits == 8:
token = "%d"
arg_val = llvmlite.build_sext(builder, arg_val, i32_ty)
elif arg_bits == 16:
token = "%d"
arg_val = llvmlite.build_sext(builder, arg_val, i32_ty)
elif arg_bits == 32:
token = "%d"
else:
token = "%lld"
elif arg_fbits != 0:
token = "%f"
if arg_fbits < 64:
arg_val = llvmlite.build_fpext(builder, arg_val, dbl_ty)
else:
# 结构体值/数组/函数等 → "(unknown)",不传参
token = "(unknown)"
chain_arg = 0
# 追加格式 token
if string.strlen(fmt_buf) < FMT_BUF_SIZE - 16:
viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 16, "%s", token)
# 链接参数
if chain_arg != 0:
arg_val.Next = None
if arg_tail is None:
arg_head = arg_val
else:
arg_tail.Next = arg_val
arg_tail = arg_val
arg_count += 1
# 追加默认换行(Python print 默认 end="\n")
if string.strlen(fmt_buf) < FMT_BUF_SIZE - 2:
viperlib.snprintf(fmt_buf + string.strlen(fmt_buf), 2, "\n")
fmt_ptr: llvmlite.Value | t.CPtr = HandlesExpr.create_global_string(
builder, pool, mod, fmt_buf, trans)
stdlib.free(fmt_buf)
if fmt_ptr is None:
return
fmt_ptr.Next = arg_head
# is_variadic=1: 带显式函数类型签名(C ABI 变参调用)
llvmlite.build_call(builder, "printf", fmt_ptr, arg_count, i32_ty, 1)
def _va_arg_get_alloca_ptr(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
arg_node: ast.AST | t.CPtr,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""获取 va_list 变量的 alloca 指针(不 load)
va_arg/va_start/va_end 需要的是 va_list 对象的地址(alloca 指针),
而非 va_list 的值。若 arg_node 是 Name,查符号表获取 alloca;
否则用 translate_value 翻译(调用者负责确保传入的是指针)。
"""
if arg_node is None:
return None
# Name 节点:直接查符号表获取 alloca 指针(不 load)
if arg_node.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(arg_node)
if nm.id is not None:
alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, nm.id)
if alloca is not None:
return alloca
# 回退:translate_value(可能返回 load 后的值,仅适用于已是指针的情况)
return HandlesExpr.translate_value(builder, pool, mod, arg_node, funcs_ptr, func_count, trans)
def _resolve_va_arg_type(self, pool: memhub.MemBuddy | t.CPtr,
type_node: ast.AST | t.CPtr,
trans: HT.Translator | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""解析 va_arg/arg 的类型参数为 LLVMType
支持的类型表达式:
t.CInt / t.CInt32T → i32
t.CInt64T → i64
t.CDouble → double
t.CPtr / t.CChar | t.CPtr → i8*
str / bytes → i8*
无类型参数时默认 i32(vsnprintf 中 va_arg(ap) 常用于读取 i32)
"""
if type_node is None:
return llvmlite.Int32(pool)
# 使用 HandlesType.resolve_annotation_type 解析类型表达式
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, type_node, trans._imported_modules, trans._from_imports, trans)
if resolved is not None:
return resolved
# 回退为 i32
return llvmlite.Int32(pool)
def _translate_va_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""va_arg(ap, type) / va_arg(ap) → %N = va_arg <ap_ty> <ap>, <type>
生成 LLVM va_arg 指令,从 va_list 读取下一个变长参数。
"""
if can == 0 or cargs is None:
return llvmlite.const_int32(pool, 0)
# 第一个参数:va_list(求值为 i8* 地址值,对齐 TPC _HandleVaArgLlvm)
# 当前函数 *args:translate_value 经 vararg 名映射直接返回 va_list 缓冲区地址;
# 转发场景(sprintf → vsnprintf 的 ap 参数):translate_value load 参数得到地址值。
ap_node: ast.AST | t.CPtr = cargs.get(0)
ap_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, ap_node, None, 0, trans)
if ap_val is None:
return llvmlite.const_int32(pool, 0)
ap_ptr: llvmlite.Value | t.CPtr = ap_val
# 第二个参数:目标类型(可选,默认 i32)
arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
if can >= 2:
type_node: ast.AST | t.CPtr = cargs.get(1)
arg_ty = self._resolve_va_arg_type(pool, type_node, trans)
# Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(对齐 TPC emit_va_arg L72-73)
read_ty: llvmlite.LLVMType | t.CPtr = arg_ty
abits_va: int = HandlesExpr.get_llvm_type_bits(arg_ty)
if abits_va != 0 and abits_va < 64:
read_ty = llvmlite.Int64(pool)
# 生成 va_arg 指令
return llvmlite.build_va_arg(builder, ap_ptr, read_ty)
def _translate_arg_sugar(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cl: ast.Call | t.CPtr,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""arg(type) → %N = va_arg <va_list_ty> <trans._va_list_ptr>, <type>
使用当前函数的隐式 va_list(trans._va_list_ptr),
简化 *args 函数体内的 va_arg 调用。
"""
if trans._va_list_ptr is None:
return llvmlite.const_int32(pool, 0)
# 第一个参数:目标类型(可选,默认 i32)
arg_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
if can >= 1 and cargs is not None:
type_node: ast.AST | t.CPtr = cargs.get(0)
arg_ty = self._resolve_va_arg_type(pool, type_node, trans)
# Win64 变参槽位为 8 字节:<64 位整数按 i64 读取(与 _translate_va_arg_sugar 一致)
read_ty: llvmlite.LLVMType | t.CPtr = arg_ty
abits_arg: int = HandlesExpr.get_llvm_type_bits(arg_ty)
if abits_arg != 0 and abits_arg < 64:
read_ty = llvmlite.Int64(pool)
# 生成 va_arg 指令(使用 trans._va_list_ptr 作为 va_list 地址)
return llvmlite.build_va_arg(builder, trans._va_list_ptr, read_ty)
def _translate_va_start_sugar(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""va_start(ap, last_arg) → call void @llvm.va_start(i8* %ap)
初始化 va_list。第二个参数 last_arg 在 LLVM intrinsic 中不使用(C 宏兼容)。
"""
if can == 0 or cargs is None:
return llvmlite.const_int32(pool, 0)
# 第一个参数:va_list 指针(获取 alloca,不 load)
ap_node: ast.AST | t.CPtr = cargs.get(0)
ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr(
pool, builder, mod, ap_node, funcs_ptr, func_count, trans)
if ap_ptr is None:
return llvmlite.const_int32(pool, 0)
# bitcast 到 i8*(@llvm.va_start 接受 i8*)
i8_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_vs)
ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_vs)
if ap_i8 is None:
return llvmlite.const_int32(pool, 0)
void_ty_vs: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
llvmlite.build_call(builder, "llvm.va_start", ap_i8, 1, void_ty_vs, 0)
return llvmlite.const_int32(pool, 0)
def _translate_va_end_sugar(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
cargs: list[ast.AST | t.CPtr] | t.CPtr,
can: t.CSizeT,
funcs_ptr: t.CPtr,
func_count: int,
trans: HT.Translator | t.CPtr) -> llvmlite.Value | t.CPtr:
"""va_end(ap) → call void @llvm.va_end(i8* %ap)
清理 va_list。在大多数平台上是 no-op,但调用它是良好的 C ABI 习惯。
"""
if can == 0 or cargs is None:
return llvmlite.const_int32(pool, 0)
# 第一个参数:va_list 指针(获取 alloca,不 load)
ap_node: ast.AST | t.CPtr = cargs.get(0)
ap_ptr: llvmlite.Value | t.CPtr = self._va_arg_get_alloca_ptr(
pool, builder, mod, ap_node, funcs_ptr, func_count, trans)
if ap_ptr is None:
return llvmlite.const_int32(pool, 0)
# bitcast 到 i8*(@llvm.va_end 接受 i8*)
i8_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty_ve)
ap_i8: llvmlite.Value | t.CPtr = llvmlite.build_bitcast(builder, ap_ptr, i8_ptr_ty_ve)
if ap_i8 is None:
return llvmlite.const_int32(pool, 0)
void_ty_ve: llvmlite.LLVMType | t.CPtr = llvmlite.Void(pool)
llvmlite.build_call(builder, "llvm.va_end", ap_i8, 1, void_ty_ve, 0)
return llvmlite.const_int32(pool, 0)
def _get_func_fixed_param_count(self, func: llvmlite.Function | t.CPtr) -> int:
"""获取函数的固定参数数量(遍历 Params 链表)"""
if func is None:
return 0
count: int = 0
param: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
while param is not None:
count += 1
param = llvmlite.param_get_next(param)
return count
def _check_and_promote_variadic_call(self, pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
call_name: str,
head: llvmlite.Value | t.CPtr,
can: t.CSizeT) -> int:
"""检查被调用函数是否为变长函数,若是则对变长参数进行 C ABI 提升
返回: is_variadic (1=变长调用, 0=普通调用)
副作用: 修改 head 链表中超过固定参数数量的节点(C ABI 提升)
"""
if mod is None or call_name is None or head is None:
return 0
# 查找函数对象
func: llvmlite.Function | t.CPtr = self.find_func_in_module(mod, call_name)
if func is None:
return 0
if func.IsVarArg != 1:
return 0
# 获取固定参数数量
fixed_count: int = self._get_func_fixed_param_count(func)
# 无变长参数(实参数量 <= 固定参数数量),仍需 is_variadic=1
if can <= fixed_count:
return 1
# 遍历到第 fixed_count 个节点(固定参数的最后一个)
cur: llvmlite.Value | t.CPtr = head
prev: llvmlite.Value | t.CPtr = None
idx: int = 0
while cur is not None and idx < fixed_count:
prev = cur
cur = cur.Next
idx += 1
# cur 指向第 fixed_count+1 个节点(第一个变长参数)
# 对变长参数进行 C ABI 提升
i32_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
double_ty_promote: llvmlite.LLVMType | t.CPtr = llvmlite.Double(pool)
while cur is not None:
next_node: llvmlite.Value | t.CPtr = cur.Next
promoted: llvmlite.Value | t.CPtr = cur
# C ABI integer promotion: i8/i16 → i32
arg_bits: int = HandlesExpr.get_llvm_type_bits(cur.Ty)
if arg_bits != 0 and arg_bits < 32:
promoted = HandlesExpr.coerce_to_type(builder, cur, i32_ty_promote, None)
if promoted is not None:
promoted.Next = next_node
if prev is not None:
prev.Next = promoted
# C ABI float promotion: float → double
arg_fbits: int = HandlesExpr.get_llvm_float_bits(promoted.Ty)
if arg_fbits != 0 and arg_fbits < 64:
promoted = HandlesExpr.coerce_to_type(builder, promoted, double_ty_promote, None)
if promoted is not None:
promoted.Next = next_node
if prev is not None:
prev.Next = promoted
prev = promoted
cur = next_node
return 1
def init_func_table(self, pool: memhub.MemBuddy | t.CPtr,
max_count: int) -> HandlesExprCall.FuncEntry | t.CPtr:
"""分配并清零函数表数组"""
size: t.CSizeT = max_count * HandlesExprCall.FuncEntry.__sizeof__()
funcs_ptr: HandlesExprCall.FuncEntry | t.CPtr = pool.alloc(size)
if funcs_ptr is not None:
string.memset(funcs_ptr, 0, size)
return funcs_ptr
def find_func_in_table(self, funcs: HandlesExprCall.FuncEntry | t.CPtr,
func_count: int,
name: str) -> llvmlite.Function | t.CPtr:
"""在函数表中按名称查找,返回 Function 指针或 None"""
if name is None or funcs is None:
return None
entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__()
for i in range(func_count):
entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size
entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
if entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
return entry.Func
return None
def add_func_to_table(self, funcs: HandlesExprCall.FuncEntry | t.CPtr,
func_count: int,
name: str,
func: llvmlite.Function | t.CPtr,
max_count: int,
defaults: t.CVoid | t.CPtr = None,
default_count: int = 0,
param_count: int = 0,
pool: memhub.MemBuddy | t.CPtr = None) -> int:
"""添加函数到函数表,返回 0 成功
Args:
defaults: ast.Arguments.defaults 列表节点指针,None=无默认值
default_count: 默认值数量(len(defaults))
param_count: 形参数量(不含 self,len(args.args))
pool: 内存池(用于生成 TypeStr;None 时 TypeStr 为空,vtable 回退读 Func 对象)
"""
if name is None or func is None or funcs is None:
return 1
if func_count >= max_count:
return 1
entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__()
entry_addr: t.CUInt64T = t.CUInt64T(funcs) + func_count * entry_size
entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
entry.Name = name
entry.Func = func
entry.Defaults = defaults
entry.DefaultCount = default_count
entry.ParamCount = param_count
# 同时注册到全局函数表(供跨模块 vtable 初始化查找)
self._register_global_func(name, func, pool)
# 同时注册到全局默认参数表(供跨模块调用时填充默认值)
if default_count > 0:
self._register_global_defaults(name, defaults, default_count, param_count)
return 0
def _init_global_func_table(self) -> int:
"""初始化全局函数表(用 stdlib.malloc 分配,生命周期=整个程序)"""
if self.GlobalFuncs is not None:
return 1
size: t.CSizeT = GLOBAL_FUNC_MAX * HandlesExprCall.FuncEntry.__sizeof__()
self.GlobalFuncs = stdlib.malloc(size)
if self.GlobalFuncs is None:
return 0
string.memset(self.GlobalFuncs, 0, size)
self.GlobalFuncCount = 0
return 1
def _build_func_type_str(self, pool: memhub.MemBuddy | t.CPtr,
func: llvmlite.Function | t.CPtr) -> t.CChar | t.CPtr:
"""生成函数类型文本(stdlib 分配)"""
if func is None:
return None
# 类型文本可能较长(SHA1 限定命名结构体 + 多参数),用 1024 缓冲
ty_buf: t.CChar | t.CPtr = pool.alloc(1024)
if ty_buf is None:
return None
ty_buf[0] = '\0'
# 返回类型
ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(func)
ret_part: t.CChar | t.CPtr = pool.alloc(512)
if ret_part is not None and ret_ty is not None:
ret_part[0] = '\0'
llvmlite.TypePrint(ret_part, 512, ret_ty, pool)
self._asm_append_cstr(ty_buf, 1024, ret_part)
self._asm_append_cstr(ty_buf, 1024, " (")
# 参数类型(全部经 _asm_append_cstr 有界追加,防止 strcat 无界写穿 1024 缓冲)
cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
first: int = 1
param_part: t.CChar | t.CPtr = pool.alloc(512)
while cur is not None:
if first == 0:
self._asm_append_cstr(ty_buf, 1024, ", ")
if param_part is not None:
param_part[0] = '\0'
param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur)
if param_ty is not None:
llvmlite.TypePrint(param_part, 512, param_ty, pool)
self._asm_append_cstr(ty_buf, 1024, param_part)
cur = llvmlite.param_get_next(cur)
first = 0
self._asm_append_cstr(ty_buf, 1024, ")")
# 深拷贝到 stdlib 区(TypeStr 跨文件永久存活)
ts_len: t.CSizeT = string.strlen(ty_buf)
ts_copy: t.CChar | t.CPtr = stdlib.malloc(ts_len + 1)
if ts_copy is None:
return None
string.strcpy(ts_copy, ty_buf)
return ts_copy
def _register_global_func(self, name: str, func: llvmlite.Function | t.CPtr,
pool: memhub.MemBuddy | t.CPtr = None) -> int:
"""注册函数到全局表(已存在则跳过),返回 0 成功
直接操作全局表,不调用 add_func_to_table,避免递归。
pool 用于生成 TypeStr(None 时 TypeStr 为空)。
"""
if name is None or func is None:
return 1
if self._init_global_func_table() == 0:
return 1
# 已存在则跳过(避免重复)
if self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name) is not None:
return 0
if self.GlobalFuncCount >= GLOBAL_FUNC_MAX:
return 1
# 直接写入全局表(不调用 add_func_to_table,避免递归)
entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__()
entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalFuncs) + self.GlobalFuncCount * entry_size
entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
# Name 深拷贝到 stdlib 区:全局表跨文件永久存活,pool 内名字会被 1b 每文件
# reset_to(mark1) 回收导致悬空(vtable 生成 find_func_global 后 strcmp 崩溃)
name_len: t.CSizeT = string.strlen(name)
name_copy: t.CChar | t.CPtr = stdlib.malloc(name_len + 1)
if name_copy is None:
return 1
string.strcpy(name_copy, name)
entry.Name = name_copy
entry.Func = func
# TypeStr 不在此生成:函数参数在 add_func_to_table 之后才添加,
# 需由调用方在参数添加完成后调用 update_global_func_typestr 补全。
self.GlobalFuncCount += 1
return 0
def update_global_func_typestr(self, pool: memhub.MemBuddy | t.CPtr,
name: str,
func: llvmlite.Function | t.CPtr) -> int:
"""更新全局函数表的 TypeStr(在函数参数全部添加完成后调用)
调用时机:add_func_to_table 注册后、llvmlite.add_param 全部执行完。
生成 ret_ty (param1_ty, ...) 类型文本(stdlib 深拷贝),
供 vtable 生成在 func 被 1b reset 后使用。
"""
if name is None or func is None:
return 1
entry: HandlesExprCall.FuncEntry | t.CPtr = self.find_func_entry_global(name)
if entry is None:
return 1
entry.TypeStr = self._build_func_type_str(pool, func)
return 0
def find_func_global(self, name: str) -> llvmlite.Function | t.CPtr:
"""在全局函数表中按名称查找,返回 Function 指针或 None"""
if name is None or self.GlobalFuncs is None:
return None
return self.find_func_in_table(self.GlobalFuncs, self.GlobalFuncCount, name)
def find_func_entry_global(self, name: str) -> HandlesExprCall.FuncEntry | t.CPtr:
"""在全局函数表中按名称查找,返回完整 FuncEntry(含 TypeStr)或 None"""
if name is None or self.GlobalFuncs is None:
return None
entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__()
for i in range(self.GlobalFuncCount):
entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalFuncs) + i * entry_size
entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
if entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
return entry
return None
def _init_global_defaults_table(self) -> int:
"""初始化全局默认参数表"""
if self.GlobalDefaults is not None:
return 1
size: t.CSizeT = GLOBAL_DEFAULTS_MAX * HandlesExprCall.FuncDefaultsEntry.__sizeof__()
self.GlobalDefaults = stdlib.malloc(size)
if self.GlobalDefaults is None:
return 0
string.memset(self.GlobalDefaults, 0, size)
self.GlobalDefaultsCount = 0
return 1
def _register_global_defaults(self, name: str,
defaults: t.CVoid | t.CPtr,
default_count: int,
param_count: int) -> int:
"""注册函数默认参数到全局表,返回 0 成功
注册时提取每个默认值 Constant 的常量快照到 stdlib(ConstKinds/ConstInts/ConstStrs),
跨模块调用时优先用快照重建常量 IR,避免读取被 reset 回收的 pool 内 AST。
"""
if name is None or defaults is None:
return 1
if self._init_global_defaults_table() == 0:
return 1
# 已存在则跳过
if self.find_func_defaults(name) is not None:
return 0
if self.GlobalDefaultsCount >= GLOBAL_DEFAULTS_MAX:
return 1
entry_size: t.CSizeT = HandlesExprCall.FuncDefaultsEntry.__sizeof__()
entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalDefaults) + self.GlobalDefaultsCount * entry_size
entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr = (HandlesExprCall.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
# Name 深拷贝到 stdlib(全局表跨文件永久存活)
nm_len: t.CSizeT = string.strlen(name)
nm_copy: t.CChar | t.CPtr = stdlib.malloc(nm_len + 1)
if nm_copy is None:
return 1
string.strcpy(nm_copy, name)
entry.Name = nm_copy
entry.Defaults = defaults
entry.DefaultCount = default_count
entry.ParamCount = param_count
# 提取常量快照到 stdlib
if default_count > 0:
kinds: t.CInt | t.CPtr = stdlib.malloc(default_count * 4)
ints: t.CInt64T | t.CPtr = stdlib.malloc(default_count * 8)
strs: t.CSizeT | t.CPtr = stdlib.malloc(default_count * 8)
if kinds is not None and ints is not None and strs is not None:
string.memset(kinds, 0, default_count * 4)
string.memset(ints, 0, default_count * 8)
string.memset(strs, 0, default_count * 8)
dl: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(t.CVoid(t.CUInt64T(defaults), t.CPtr))
di: int
for di in range(default_count):
dnode: ast.AST | t.CPtr = dl.get(di)
if dnode is not None and dnode.kind() == ast.ASTKind.Constant:
dcn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(dnode)
kinds[di] = dcn.const_kind
ints[di] = dcn.int_val
if dcn.const_kind == ast.CONST_STR and dcn.str_val is not None:
slen: t.CSizeT = string.strlen(dcn.str_val)
scopy: t.CChar | t.CPtr = stdlib.malloc(slen + 1)
if scopy is not None:
string.strcpy(scopy, dcn.str_val)
strs[di] = t.CSizeT(scopy)
entry.ConstKinds = kinds
entry.ConstInts = ints
entry.ConstStrs = strs
self.GlobalDefaultsCount += 1
return 0
def find_func_defaults(self, name: str) -> HandlesExprCall.FuncDefaultsEntry | t.CPtr:
"""按函数名查找默认参数信息,返回 FuncDefaultsEntry 或 None"""
if name is None or self.GlobalDefaults is None:
return None
entry_size: t.CSizeT = HandlesExprCall.FuncDefaultsEntry.__sizeof__()
i: int = 0
while i < self.GlobalDefaultsCount:
entry_addr: t.CUInt64T = t.CUInt64T(self.GlobalDefaults) + i * entry_size
entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr = (HandlesExprCall.FuncDefaultsEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
if entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
return entry
i += 1
return None
def _build_const_from_snapshot(self, pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
gd_entry: HandlesExprCall.FuncDefaultsEntry | t.CPtr,
di: int,
trans: HT.Translator | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr) -> llvmlite.Value | t.CPtr:
"""从快照重建第 di 个默认值常量 IR"""
if gd_entry is None or gd_entry.ConstKinds is None or gd_entry.ConstInts is None:
return None
if di < 0 or di >= gd_entry.DefaultCount:
return None
kind: t.CInt = gd_entry.ConstKinds[di]
ival: t.CInt64T = gd_entry.ConstInts[di]
if kind == ast.CONST_INT:
if ival > 2147483647 or ival < -2147483648:
return llvmlite.const_int64(pool, ival)
return llvmlite.const_int32(pool, ival)
elif kind == ast.CONST_BOOL:
if ival != 0:
return llvmlite.const_int32(pool, 1)
return llvmlite.const_int32(pool, 0)
elif kind == ast.CONST_NONE:
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
return llvmlite.ConstNull(pool, i8_ptr_ty, "null")
elif kind == ast.CONST_STR:
if gd_entry.ConstStrs is not None and gd_entry.ConstStrs[di] != 0:
sv: str = (str | t.CPtr)(t.CVoid(gd_entry.ConstStrs[di], t.CPtr))
return HandlesExpr.create_global_string(builder, pool, mod, sv, trans)
# 无法重建的(如 CONST_FLOAT/复杂表达式)返回 None,调用方回退到 AST
return None
def find_func_entry_in_table(self, funcs: HandlesExprCall.FuncEntry | t.CPtr,
func_count: int,
name: str) -> HandlesExprCall.FuncEntry | t.CPtr:
"""在函数表中按名称查找,返回完整 FuncEntry 或 None"""
if name is None or funcs is None:
return None
entry_size: t.CSizeT = HandlesExprCall.FuncEntry.__sizeof__()
i: int = 0
while i < func_count:
entry_addr: t.CUInt64T = t.CUInt64T(funcs) + i * entry_size
entry: HandlesExprCall.FuncEntry | t.CPtr = (HandlesExprCall.FuncEntry | t.CPtr)(t.CVoid(entry_addr, t.CPtr))
if entry.Name is not None:
if string.strcmp(entry.Name, name) == 0:
return entry
i += 1
return None
def NewExprCallHandle(self, pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> HandlesExprCall.ExprCallHandle | t.CPtr:
h: HandlesExprCall.ExprCallHandle | t.CPtr = pool.alloc(HandlesExprCall.ExprCallHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, HandlesExprCall.ExprCallHandle.__sizeof__())
h.Trans = trans
return h