Files
ViperC/App/lib/core/Gen/Translator.vp
T
TermiNexus 981af07d5c fix(phase): App 预注册期注入依赖 vpi,修 list[ast.ClassDef*] 票名前缀分裂
Phase A-pre(App 预注册)此前不做导入处理、不注入依赖 .vpi,导致包重导出
类的字段注解在预注册期只能保留「包前缀」(1abcd…),并被冻结进结构体布局;
阶段 A 构造函数侧却能借包别名 entry 校正为真定义前缀(e70bd…),两处票名
分裂 ⇒「非基本类型指针不可隐式转换」(现场 ClassGenGeneric.vp:92)。

改动(只放开 App 预注册,不动 includes 预注册那条防依赖环自锁的约束):
- Translator 新增 _pre_allow_dep_inject 开关,并在导入处理门拆成两道:
  ①导入处理 + 自动容器可见性 + LoadDepVpiIntoModule —— 全量翻译与 App 预注册共用;
  ②模块级变量预注册 + 函数前向声明 —— 仍只在全量翻译做。
- BuildPipeline.TranslateFileGetTrans 新增 pre_allow_dep_inject 参数并写入 Translator。
- Phase2 App 预注册调用点传 1;includes 预注册保持默认 0。
2026-10-02 01:03:31 +08:00

1026 lines
53 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 lib.core.Gen.GenApi as GenApi
import lib.core.Gen.GenTypes as GenTypes
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
import viperlib
import lib.core.VLogger as VLogger
import lib.Projectrans.Config as Config
import lib.Stub.StubMerger.StubMergerBuild as StubMergerBuild
import lib.Stub.StubMerger.StubMergerStore as StubMergerStore
import lib.core.Gen.Generator as Generator
import lib.core.Gen.DebugInfoGen as DebugInfoGen
# ============================================================
# Gen/Translator.vp - 翻译器状态管理 + 主入口
#
# 负责: 1) Translator 类(状态管理:Module/变量表/函数表/导入)
# 2) translate() 主翻译入口 3) dump_ir() IR 输出
# global/nonlocal 名称管理委托函数在 lib.core.Gen.GenApi,
# TranslatorGenMixin 侧另有同名一行委托。
# ============================================================
# ============================================================
# HandlesTranslator - 翻译器状态管理 + 主入口
#
# 从 translator.py 拆分出来,负责:
# 1. Translator 类 - 状态管理(Module, 变量表, 函数表, 导入)
# 2. translate() - 主翻译入口
# 3. dump_ir() - IR 输出
#
# 语句/表达式翻译全部委托给 Handles 模块:
# HandlesMain - wrapper main 创建 + children 遍历
# HandlesBody - 语句分派
# HandlesExpr - 表达式翻译
# HandlesFunctions - 函数定义处理
# 注意:str = bytes = str = i8*
#
# P6-E 对象化重构:模块级 global/nonlocal 名称管理函数已迁移为
# lib.core.Gen.TranslatorGenMixin 的方法,本模块保留同名模块级
# 函数作为"一行委托"(同 P2-P5 模式)。Translator 类保留在本模块。
# ============================================================
# 常量
# 作用域变量表容量上限(唯一真源)。分配点 VarGenMixin.init_vars
# (HT.MAX_VARS * VarEntry.__sizeof__())与守卫 VarGenMixin.add_var
# (var_count >= HT.MAX_VARS)都取本常量,两者结构上不可能各自漂移。
define MAX_VARS = 1024
# 函数表容量上限(唯一真源)。分配点在本模块 _init_state
# (GenApi.init_func_table(pool, MAX_FUNCS));注册侧守卫上限由
# FuncGenDef/ClassGenVTable/AsyncGenMixin/VpiReader 传给
# CallGenLeafKit.add_func_to_table 的 max_count 给出,必须 <= 本容量。
define MAX_FUNCS = 1024
# 引用口径(同 CallGenBase.vp 常量段):跨模块 t.CDefine 只能在函数体内读,
# 故引用方一律写限定名 HT.MAX_VARS / HT.MAX_FUNCS,且不得用于模块级
# CDefine 初始化式。
# global/nonlocal 名称表容量上限(唯一真源)。TranslatorGenMixin 的
# add_global_name/add_nonlocal_name 越界守卫与 FuncGenMixin 的嵌套 nonlocal
# 缓冲分配均经 HT.MAX_GLOBAL_NAMES 引用本常量;缓冲分配(Translator._init_state)
# 与守卫必须同值,单改任一侧都会造成堆越界写或有效容量缩水。
define MAX_GLOBAL_NAMES = 128
# 协程表容量(TPV-M1):async 函数数 / 协程变量·局部名数
define MAX_CORO_FUNCS = 256
define MAX_CORO_VARS = 256
define MAX_CORO_TRY = 16
# 翻译主环最大递归深度(translate_stmt/translate_value 嵌套)。AST 自引用环
# 或翻译 bug 可致翻译主环(语句/表达式/调用)无限递归 → ASan stack-overflow。
# match 守卫(MatchTranslateDepth)只保护 match 递归,本常量保护语句/表达式
# 翻译环(fail-fast,对齐 TypeGenResolve 深度守卫模式)。
define TRANSLATE_MAX_DEPTH = 256
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
# ============================================================
novirtual class Translator:
"""翻译器:管理编译状态,委托 Handles 模块执行翻译"""
# LLVM 上下文(共享状态)
Module: llvmlite.LLVMModule*
Pool: memhub.MemBuddy*
# 函数表
_funcs: GenTypes.FuncEntry*
_func_count: int
# 协程(TPV-M1 async def / await / coro.coro_run)
# _async_funcs: 已注册 async 函数裸名表(char* 数组,8 字节/项)
# _coro_var_async: 变量名→async 函数名 成对表(char* 数组,16 字节/项)
# _coro_locals: 当前 async 函数局部变量名表(char* 数组,8 字节/项)
# _coro_frames: async 名→帧类型 成对表(16 字节/项 = char* + LLVMType*)
_async_funcs: str
_async_func_count: int
_coro_var_async: str
_coro_var_async_count: int
_coro_locals: str
_coro_local_count: int
_coro_frames: str
_coro_frame_count: int
# resume_<name> 翻译上下文(AsyncGenMixin 段翻译共享)
_coro_state_ptr: llvmlite.Value*
_coro_done_ptr: llvmlite.Value*
_coro_ret_ptr: llvmlite.Value*
_coro_exit_bb: rawptr[llvmlite.BasicBlock]
_coro_await_slot: llvmlite.Value*
_coro_frame: llvmlite.Value*
_coro_next_state: int
_coro_nseg: int
# M2:async 参数表(char* 数组,8 字节/项)+ 预扫描计数
_coro_params: str
_coro_param_count: int
_coro_hoist_count: int # __await_N 槽计数(预扫描与翻译共用,序一致)
_coro_await_count: int # 总 await 数(= 恢复块数 = switch case 数)
_coro_local_base: int # 局部槽起始 index(= 3 + nparams)
_coro_extra_base: int # 额外槽(__await_N)起始 index
_coro_break_bb: rawptr[llvmlite.BasicBlock] # While break 目标(M2 单层)
_coro_continue_bb: rawptr[llvmlite.BasicBlock] # While continue 目标
_coro_state_bbs: sizet* # 预建 state 块数组(await 恢复块定位)
# M3-M7 协程扩展
_coro_exc_ptr: llvmlite.Value* # 帧 exc 槽(i32,M4)
_coro_msg_ptr: llvmlite.Value* # 帧 msg 槽(i8*,M7)
_coro_wake_ptr: llvmlite.Value* # 帧 wake 槽(i64,M3 coro_sleep)
_coro_try_stack: sizet* # try 栈:except/finally 块指针数组(8B/项)
_coro_try_stack_count: int
_coro_for_counter: int # range-For 编号(M3,翻译期递增)
_coro_scan_for_count: int # 预扫描期 For 计数
_coro_uses_sleep: int # 函数体是否用 coro_sleep(预扫描置位)
_coro_extra_types: str # 额外槽类型表(i8 数组:1=i32 2=i64)
_coro_extra_count: int # 额外槽总数
_coro_await_slots: int | t.CPtr # __await_N 的帧相对槽 index(预扫描填)
_coro_for_slots: int | t.CPtr # range-For N 的 __f_idx 帧相对槽 index(预扫描填)
# per-async wake 槽 index 表(coro_run/gather 轮询反查用)
_coro_wake_names: str # char* 数组(8B/项)
_coro_wake_idxs: int | t.CPtr # i32 数组(4B/项,-1=无 wake 槽)
_coro_wake_count: int
# 导入模块跟踪
_imported_modules: str
_from_imports: str
# 当前翻译上下文
_cur_func: llvmlite.Function*
_cur_builder: llvmlite.IRBuilder*
# 当前赋值语句的注解节点(AnnAssign 翻译 rhs 前设置,Assign 翻译前清空)。
# 供裸名泛型构造从注解推断类型实参:`s: Stack[int] = Stack()` 用注解里的
# int 特化(消费者见 CallGenCtor.vp 的 CurAssignNode/CurAssignAnnot 判定)。
CurAssignAnnot: ast.AST*
# 当前赋值语句的 RHS 节点(AnnAssign 翻译 rhs 前设置,rhs 翻译后清除)。
# 供裸名泛型构造判定"构造调用是否为赋值直接 RHS":仅该 identity 命中时才用
# CurAssignAnnot 推断类型实参(对齐 TPC 的直接 RHS 检查)。
CurAssignNode: ast.AST*
# 当前函数的返回注解节点(translate_function_def 进入函数体前设置,退出时
# 恢复外层函数的值)。供裸名泛型构造回退推断类型实参:`-> Stack[int]` 里
# `return Stack()` 用注解里的 int 特化(与 CurAssignAnnot 同类的上下文通道)。
CurFuncRetAnnot: ast.AST*
# 当前 Return 语句的直接值节点(translate_return 翻译返回值前设置,翻译后
# 清除)。与 CurAssignNode 同款的 identity 判定:仅「裸名泛型构造就是 return
# 的直接值」时才用 CurFuncRetAnnot(嵌套调用如 return f(Stack()) 不推断)。
CurRetNode: ast.AST*
# 循环控制流目标(break/continue)
_break_bb: rawptr[llvmlite.BasicBlock]
_continue_bb: rawptr[llvmlite.BasicBlock]
# 独立标签计数器(不与 builder.Counter 共享,避免 SSA 编号非单调)
_label_counter: int
# 追加90:控制流 merge 块可达性(1=有 br 进入可达/0=全分支 return 结构性不可达)
_ctrl_merge_reachable: int
# match 翻译递归深度(match → case body → translate_value → 嵌套 match)。
# 守卫:AST 自引用环(子节点回指祖先)或翻译 bug 导致的无限递归在此
# fail-fast(对齐 TypeGenResolve 深度守卫,防 ASan stack-overflow)。
MatchTranslateDepth: int
# 翻译主环递归深度(translate_stmt/translate_value 入口计数)。match 守卫
# 只覆盖 match 递归;语句/表达式/调用环(如 translate_value ↔ translate_call)
# 由本字段守卫,超 TRANSLATE_MAX_DEPTH 即 fail-fast(防 ASan stack-overflow)。
TranslateDepth: int
# global 声明的变量名集合(当前函数内)
_global_names: str
_global_name_count: int
# nonlocal 声明的变量名集合(当前函数内)
_nonlocal_names: str
_nonlocal_name_count: int
# nonlocal 变量的类型信息(LLVMType 指针数组,与 _nonlocal_names 一一对应)
# 用于 env 指针数组方案:子函数访问 nonlocal 变量时需要知道原始类型
_nonlocal_types: str
# 闭包相关:当前函数名(用于嵌套函数提升命名)
_cur_func_name: str
# *args 变长参数支持:当前函数的 va_list 指针(i8* alloca)
# 仅当函数声明了 *args 时设置,供 arg(type) 糖函数使用
_va_list_ptr: llvmlite.Value*
# *args 参数名(如 "args"),用于符号表注册
_vararg_name: str
# OOP iter 协议:当前 __next__ 方法的隐藏 stop-flag 参数(i1*)。
# _translate_method 注入 __stop_iter_flag__ 参数时设置;translate_raise
# 检测 raise StopIteration 时对该指针 store 1(对齐 TPC HandlesRaise.py)。
# 非 __next__ 函数中为 None。
_stop_iter_flag_ptr: llvmlite.Value*
# try-except 机制(对齐 TPC HandlesTry.py):当前最内层 try 的
# 分发块 + 异常编码/消息 alloca。translate_try 设置,translate_raise
# 与调用侧 EH 检测写入/跳转。try 外为 None。
_eh_dispatch_bb: rawptr[llvmlite.BasicBlock]
_eh_code_ptr: llvmlite.Value*
_eh_msg_ptr: llvmlite.Value*
# 当前函数的 __eh_msg_out__(i8**)/__eh_code_out__(i32*)输出参数
# (函数签名含 raise 时由 translate_function_def/_translate_method 注入)。
# 无 EH 参数时 _cur_func_has_eh == 0。
_eh_msg_out_param: llvmlite.Value*
_eh_code_out_param: llvmlite.Value*
_cur_func_has_eh: int
# 模块 SHA1 前缀(16 字符),用于函数名混淆(SHA1 命名空间)
ModuleSha1: str
# 当前文件所属包名(如 "llvmlite"),用于解析相对导入(from . import ...)
# None 表示当前文件是顶级模块(无包),相对导入无法解析
CurrentPackage: str
# 闭包 env 中的 nonlocal 变量偏移映射(每个 nonlocal 变量在 env 中的字节偏移)
_closure_env_offsets: int
_closure_env_count: int
# lambda 表达式全局唯一 ID 计数器(生成提升函数名 __lambda_{id})
# 独立于 _closure_env_count:后者随函数进入被 clear_scope_names 重置,
# lambda ID 需跨函数全局唯一(提升函数名避免冲突)
_lambda_count: int
# 函数链内 nonlocal 变量集合(预扫描收集,含嵌套函数声明的 nonlocal)。
# 用于"不同层捕获不同变量"场景(如 level1→a, level2→b):b 定义在最外层
# 但 level1 不捕获——level1 env 无 b 槽,level2 无法经 env 链获取 b 的堆。
# 解决:在最外层函数中为链内所有 nonlocal 建堆,并把堆地址 store 到
# 模块级映射变量 @nlheap.{sha1}.{name};内层闭包创建时从映射 load。
_nl_chain_names: t.CPtr
_nl_chain_count: int
# 链内 nonlocal 堆预建标志(每函数只建一次):translate_function_def 进入
# 新函数时重置为 0;_prepare_chain_nonlocals 首次调用置 1。多个嵌套函数
# 定义共享同一堆(防重复 malloc + 二次重定向 VarEntry.Alloca)。
_nl_chain_done: int
# 泛型特化上下文:当前正在特化的类型参数名/实参名列表
# 由 _specialize_generic_class 设置,方法体翻译时用于将 T 替换为具体类型
# None 表示不在泛型特化上下文中
GenericTypeParamNames: list[str]*
GenericTypeArgs: list[str]*
# Phase 1a 声明模式标志:1=只注册 struct/enum/union 不翻译代码体,0=全量翻译
_declare_only: int
# App 预注册(Phase A-pre)专用开关:置 1 时,即使 _declare_only != 0 也执行
# 导入语句处理与 LoadDepVpiIntoModule(依赖 stub 注入),使**类字段注解在预注册期
# 就与阶段 A 处于同一上下文**。
# 为什么需要:预注册期要注册类的字段类型,而包重导出类的票名前缀校正
# (`_class_true_def_sha1`)依赖包 __init__ 注入时登记的别名 entry;预注册期不注入
# ⇒ 只能保留**包前缀**,该票名被冻结进结构体布局,与阶段 A 构造函数侧解析出的
# 真定义前缀分裂 ⇒「指针隐式转指针已禁止」(现场 ClassGenGeneric.vp:92,
# `list[ast.ClassDef*]`:预注册得 1abcd….ClassDef*、阶段 A 得 e70bd….ClassDef*)。
# 只对 **App 预注册**置位:includes 预注册(Phase A-pre-inc)必须保持不注入,
# 否则依赖环自锁(见下方 `_declare_only == 0` 门处注释)。
_pre_allow_dep_inject: int
# 嵌套作用域符号表
SymTab: rawptr[GenTypes.SymbolTable]
# REPL 模式上下文(M2 会话变量):None ⇒ 非 REPL(普通编译路径逐字不变)。
# 仅 Repl.vp 在翻译片段前置位、翻译后清空;Gen 侧全部会话槽拦截点以
# `trans.ReplCtx is not None` 为唯一守卫。
ReplCtx: rawptr[GenTypes.ReplCtx]
def __init__(self):
self.Module = None
self.Pool = None
self._funcs = None
self._func_count = 0
self._cur_func = None
self._cur_builder = None
self._break_bb = None
self._continue_bb = None
self._label_counter = 0
self._imported_modules = None
self._from_imports = None
self._global_names = None
self._global_name_count = 0
self._nonlocal_names = None
self._nonlocal_name_count = 0
self._nonlocal_types = None
self._cur_func_name = None
self._va_list_ptr = None
self._vararg_name = None
self._stop_iter_flag_ptr = None
self._eh_dispatch_bb = None
self._eh_code_ptr = None
self._eh_msg_ptr = None
self._eh_msg_out_param = None
self._eh_code_out_param = None
self._cur_func_has_eh = 0
self.ModuleSha1 = None
self.CurrentPackage = None
self._closure_env_offsets = 0
self._closure_env_count = 0
self._lambda_count = 0
self._nl_chain_names = None
self._nl_chain_count = 0
self._nl_chain_done = 0
self.GenericTypeParamNames = None
self.GenericTypeArgs = None
self._declare_only = 0
self._pre_allow_dep_inject = 0
self.SymTab = None
# REPL 模式上下文:默认未设置(= 非 REPL,Gen 侧拦截全部旁路)
self.ReplCtx = None
self._async_funcs = None
self._async_func_count = 0
self._coro_var_async = None
self._coro_var_async_count = 0
self._coro_locals = None
self._coro_local_count = 0
self._coro_frames = None
self._coro_frame_count = 0
self._coro_state_ptr = None
self._coro_done_ptr = None
self._coro_ret_ptr = None
self._coro_exit_bb = None
self._coro_await_slot = None
self._coro_frame = None
self._coro_next_state = 1
self._coro_nseg = 0
self._coro_params = None
self._coro_param_count = 0
self._coro_hoist_count = 0
self._coro_await_count = 0
self._coro_local_base = 3
self._coro_extra_base = 3
self._coro_break_bb = None
self._coro_continue_bb = None
self._coro_state_bbs = None
self._coro_exc_ptr = None
self._coro_msg_ptr = None
self._coro_wake_ptr = None
self._coro_try_stack = None
self._coro_try_stack_count = 0
self._coro_for_counter = 0
self._coro_scan_for_count = 0
self._coro_uses_sleep = 0
self._coro_extra_types = None
self._coro_extra_count = 0
self._coro_await_slots = None
self._coro_for_slots = None
self._coro_wake_names = None
self._coro_wake_idxs = None
self._coro_wake_count = 0
# ============================================================
# 状态初始化
# ============================================================
def _init_state(self, pool: memhub.MemBuddy*):
"""初始化变量表、函数表和子 Handle"""
self.Pool = pool
if self._funcs is None:
self._funcs = GenApi.init_func_table(pool, MAX_FUNCS)
# 嵌套作用域符号表(新版)
if self.SymTab is None:
self.SymTab = GenApi.init_symbol_table(pool)
# global/nonlocal 名称集合缓冲区(MAX_GLOBAL_NAMES 个 char* 指针 = 128*8 字节)
if self._global_names is None:
self._global_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
if self._global_names is not None:
string.memset(self._global_names, 0, MAX_GLOBAL_NAMES * 8)
self._global_name_count = 0
if self._nonlocal_names is None:
self._nonlocal_names = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
if self._nonlocal_names is not None:
string.memset(self._nonlocal_names, 0, MAX_GLOBAL_NAMES * 8)
self._nonlocal_name_count = 0
# nonlocal 变量类型数组(LLVMType 指针数组,与 _nonlocal_names 一一对应)
if self._nonlocal_types is None:
self._nonlocal_types = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
if self._nonlocal_types is not None:
string.memset(self._nonlocal_types, 0, MAX_GLOBAL_NAMES * 8)
# 协程表(TPV-M1):async 函数名 / 变量→async 映射 / 局部名 / 帧类型
if self._async_funcs is None:
self._async_funcs = stdlib.malloc(MAX_CORO_FUNCS * 8)
if self._async_funcs is not None:
string.memset(self._async_funcs, 0, MAX_CORO_FUNCS * 8)
self._async_func_count = 0
if self._coro_var_async is None:
self._coro_var_async = stdlib.malloc(MAX_CORO_VARS * 16)
if self._coro_var_async is not None:
string.memset(self._coro_var_async, 0, MAX_CORO_VARS * 16)
self._coro_var_async_count = 0
if self._coro_locals is None:
self._coro_locals = stdlib.malloc(MAX_CORO_VARS * 8)
if self._coro_locals is not None:
string.memset(self._coro_locals, 0, MAX_CORO_VARS * 8)
if self._coro_params is None:
self._coro_params = stdlib.malloc(MAX_CORO_VARS * 8)
if self._coro_params is not None:
string.memset(self._coro_params, 0, MAX_CORO_VARS * 8)
if self._coro_try_stack is None:
self._coro_try_stack = stdlib.malloc(MAX_CORO_TRY * 8)
if self._coro_try_stack is not None:
string.memset(self._coro_try_stack, 0, MAX_CORO_TRY * 8)
if self._coro_extra_types is None:
self._coro_extra_types = stdlib.malloc(MAX_CORO_VARS)
if self._coro_extra_types is not None:
string.memset(self._coro_extra_types, 0, MAX_CORO_VARS)
if self._coro_await_slots is None:
self._coro_await_slots = stdlib.malloc(MAX_CORO_VARS * 4)
if self._coro_await_slots is not None:
string.memset(self._coro_await_slots, 0, MAX_CORO_VARS * 4)
if self._coro_for_slots is None:
self._coro_for_slots = stdlib.malloc(MAX_CORO_VARS * 4)
if self._coro_for_slots is not None:
string.memset(self._coro_for_slots, 0, MAX_CORO_VARS * 4)
if self._coro_wake_names is None:
self._coro_wake_names = stdlib.malloc(MAX_CORO_FUNCS * 8)
if self._coro_wake_names is not None:
string.memset(self._coro_wake_names, 0, MAX_CORO_FUNCS * 8)
if self._coro_wake_idxs is None:
self._coro_wake_idxs = stdlib.malloc(MAX_CORO_FUNCS * 4)
if self._coro_wake_idxs is not None:
string.memset(self._coro_wake_idxs, 0, MAX_CORO_FUNCS * 4)
self._coro_local_count = 0
if self._coro_frames is None:
self._coro_frames = stdlib.malloc(MAX_CORO_FUNCS * 16)
if self._coro_frames is not None:
string.memset(self._coro_frames, 0, MAX_CORO_FUNCS * 16)
self._coro_frame_count = 0
# ============================================================
# 主翻译入口
# ============================================================
def translate(self, tree: ast.AST*) -> int:
"""将 AST 翻译为 LLVM IR"""
if tree is None:
return 1
if _mbuddy is None:
return 1
pool: memhub.MemBuddy* = _mbuddy
# OOM 归属:把「阶段/当前模块」写进 memhub 的分配上下文。池耗尽时 memhub 会打印
# ctx=阶段/模块,从而知道是在翻译哪个模块时被吃满(SetAllocCtx 只存指针不拷贝,
# ModuleSha1 由调用方在 translate 前设置且与本次翻译同寿命)。此前无人设置该上下文。
memhub.SetAllocCtx("translate", self.ModuleSha1)
# 初始化状态
self._init_state(pool)
# 创建 LLVM 模块
mod: llvmlite.LLVMModule* = llvmlite.new_module(pool, "main")
if mod is None:
VLogger.error("NewModule returned NULL", "TR")
return 1
self.Module = mod
# --traceback: reset per-module DWARF state (no-op when DI is disabled).
DebugInfoGen.BeginModule(mod, GenApi.get_current_file())
# 设置目标(优先使用 project.vpj 中的配置)
triple: str = Config.TargetTriple
if triple is None:
triple = "x86_64-pc-windows-msvc"
llvmlite.module_set_target(mod, triple)
# 类型
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
# 声明 printf
printf_func: llvmlite.Function* = llvmlite.create_declare(pool, mod, "printf", i32_ty)
if printf_func is None:
VLogger.error("CreateDeclare printf returned NULL", "TR")
return 1
llvmlite.add_param(pool, printf_func, i8_ptr_ty, "fmt")
printf_func.IsVarArg = 1
# 声明 LLVM va_start/va_end intrinsic(供 *args 函数体内使用)
# declare void @llvm.va_start(i8*)
# declare void @llvm.va_end(i8*)
void_ty_decl: llvmlite.LLVMType* = llvmlite.Void(pool)
va_start_func: llvmlite.Function* = llvmlite.create_declare(pool, mod, "llvm.va_start", void_ty_decl)
if va_start_func is not None:
llvmlite.add_param(pool, va_start_func, i8_ptr_ty, "ap")
va_end_func: llvmlite.Function* = llvmlite.create_declare(pool, mod, "llvm.va_end", void_ty_decl)
if va_end_func is not None:
llvmlite.add_param(pool, va_end_func, i8_ptr_ty, "ap")
# 声明 malloc(闭包分配用)
malloc_func: llvmlite.Function* = llvmlite.create_declare(pool, mod, "malloc", i8_ptr_ty)
if malloc_func is not None:
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
llvmlite.add_param(pool, malloc_func, i64_ty, "size")
# 检查用户是否定义了 main 函数
has_user_main: int = 0
ch: list[ast.AST*]* = tree.children
if ch is not None:
cn_count: sizet = len(ch)
for ci in range(cn_count):
child: ast.AST* = ch.get(ci)
if child is not None and child.kind() == ast.ASTKind.FunctionDef:
fd: ast.FunctionDef* = ast.FunctionDef*(child)
if fd is not None and fd.name is not None:
if string.strcmp(fd.name, "main") == 0:
has_user_main = 1
break
if self._declare_only != 0:
# Phase 1a-pre(2=import扫描) / Phase 1a(1=struct注册): 只处理模块级,不创建 main 函数和 builder
self._translate_module_level(pool, mod, tree)
elif has_user_main == 0:
# 无用户 main → 只翻译模块级语句,不创建 wrapper main
# (避免每个文件都生成 define i32 @main() 导致链接冲突;只有 def main() 的入口文件才生成)
self._translate_module_level(pool, mod, tree)
else:
# 用户已定义 main → 委托 HandlesMain 翻译模块级
self._translate_module_level(pool, mod, tree)
# --traceback: register module-level !llvm.dbg.cu / !llvm.module.flags
# before the caller dumps the IR. Idempotent; no-op when no define got a
# DISubprogram (stub / _declare_only) or when DI is disabled.
DebugInfoGen.Finalize(pool)
return 0
# ============================================================
# 包装 main 函数(无用户 main 时)→ 委托 HandlesMain
# ============================================================
def _translate_wrapper_main(self, pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
tree: ast.AST*,
i32_ty: llvmlite.LLVMType*):
"""委托 GenApi.create_wrapper_main() 创建包装 main(trans 单参)"""
added: int = GenApi.create_wrapper_main(self, tree, i32_ty)
# ============================================================
# 模块级翻译(用户已定义 main)→ 委托 HandlesMain
# ============================================================
def _translate_module_level(self, pool: memhub.MemBuddy*,
mod: llvmlite.LLVMModule*,
tree: ast.AST*):
"""委托 GenApi.translate_children() 翻译模块级语句(trans 单参)"""
# 【文件级类名预登记:三种模式都必须先做(2026-09-30)】
# `_norm_type_arg_name` 规则 5.5 的第五类证据(is_file_class +
# get_file_module_sha1)**只由本调用建立**,而下方 prologue 整块被
# `_declare_only == 0` 门住 ⇒ Phase 1a(_declare_only == 1)的
# `_prescan_funcdef_signatures` 解析**模块级函数签名**注解时,证据⑤ 恒落空:
# 现场 includes/ast/base.vp —— 类型实参裸名 'AST' 的 ①②③④ 也全落空
# (该类尚未 register_struct;"类定义窗口"还停在更早的 enum ASTFlag,
# CurDefClassName 不会在类结束后复位)⇒ 实参特化名被冻结成**裸名**版本,
# 与 1b 全量翻译期解析出的带 SHA1 形式分裂成两个特化结构体名,最终以
# "非基本类型指针不可隐式转换"报出。
# 登记只依赖 tree + 本文件模块 SHA1,与导入、类定义窗口、类定义顺序都无关,
# 故提到门之前,三种模式(1a=1 / 1a-pre=2 / 全量=0)共用。
GenApi.register_file_classes(pool, self.ModuleSha1, tree)
# 本文件顶层函数名预登记(同址、同目的):依赖 vpi 注入的**裸名**声明
# (extern/state/export 不带 SHA1 前缀)若与本文件自己的声明同名,会先占用
# 该名字,使本文件声明在 forward_declare_functions 被静默丢弃(调用点改按
# 依赖签名 coerce)。现场:includes/socket.vp 的 extern def connect 被
# w32.winsock2 的 connect 顶掉 → socket.vp:236 报
# 「指针隐式转指针已禁止:SocketAddr* → WSASocketAddr*」。
GenApi.register_file_funcs(pool, tree)
# 先处理导入语句,再创建前向声明,解决前向引用问题。
# 两道门分开:
# ① 导入处理 + 自动容器可见性 + 依赖 vpi 注入 —— 全量翻译**与 App 预注册**
# (_pre_allow_dep_inject,见 Translator 字段说明)都要做,使类字段注解
# 在预注册期即与阶段 A 同上下文(否则包重导出类的票名前缀会分裂:
# list[ast.ClassDef*] 现场);
# ② 模块级变量预注册 + 函数前向声明 —— 仍只在全量翻译做(声明期跳过,
# 保持 Phase A-pre 的"只注册 struct/enum/union"语义)。
# includes 预注册(Phase A-pre-inc)两者都不做:_pre_allow_dep_inject 只由
# App 预注册置位,避免依赖环自锁。
if self._declare_only == 0 or self._pre_allow_dep_inject != 0:
# 预处理导入语句,确保 _imported_modules 和 _from_imports 已填充
# (前向声明需要解析类型注解,如 t.CArray[str] 依赖 t 模块已导入)
# 记录最后处理的 import 行号,供 vpi 注入错误上下文帧定位
cur_imp_lineno: int = 0
ch: list[ast.AST*]* = tree.children
if ch is not None:
cn_count: sizet = len(ch)
for ci in range(cn_count):
child: ast.AST* = ch.get(ci)
if child is None:
continue
kd: int = child.kind()
if kd == ast.ASTKind.Import:
cur_imp_lineno = child.lineno
GenApi.translate_import(self, child)
elif kd == ast.ASTKind.ImportFrom:
cur_imp_lineno = child.lineno
GenApi.translate_import_from_module(self, child)
GenApi.translate_import_from_names(self, child)
# 对齐 TPC _inject_auto_imports:检测源文件对 list/dict 容器的使用
# (裸名注解 d: dict / 构造 dict(...) / 下标 list[T]),自动把容器
# 类标记为可见结构体。背景:_list.vp/_dict.vp 定义内建容器类且已由
# Phase1 注册,但源文件不显式 import 它们(TPC 在翻译前自动注入
# import _list/_dict);TPV 用可见性机制等效替代——否则裸名
# `d: dict` 注解 resolve_annotation_type 时 is_struct_visible=0
# 解析失败(DictTest 的 "变量类型注解解析失败")。
self._inject_auto_container_visibility(pool, tree)
# CTypedef 声明由 Phase1 1b 文本扫描注册(RegisterCTypedefFromSource)——
# AST 字符串字段 token 零拷贝指向 src_buf,跨阶段内容不稳定,此处 AST 扫描
# 读 attr 会 0xC0000005,故移除。
# 跨模块 .vpi 注入:加载依赖模块的 .vpi,把函数 declare 注入当前模块。
# 注入条件 = 全量翻译,或 **App 预注册**(_pre_allow_dep_inject):后者必须
# 与阶段 A 同上下文,否则预注册期解析出的类字段票名(包重导出类的
# 真定义前缀校正依赖包别名 entry)会与阶段 A 分裂。includes 预注册
# (Phase A-pre-inc)不置位该开关 ⇒ 仍不注入,避免依赖环自锁。
if self._imported_modules is not None:
# 错误上下文帧:当前模块触发依赖 stub 加载的 import 位置
GenApi.push_trace(GenApi.get_current_file(), cur_imp_lineno)
StubMergerBuild.LoadDepVpiIntoModule(pool, mod, self._imported_modules, self._from_imports, GenApi.get_temp_dir(), self)
GenApi.pop_trace()
# 文件级类名预登记已提前到本函数开头执行(覆盖三种 _declare_only 模式;
# 为什么必须早于模块级变量/前向声明,见那里的说明)。
# 模块级变量预注册 + 函数前向声明:仍**只在全量翻译**做(声明期跳过,
# 保持 Phase A-pre"只注册 struct/enum/union"的语义)。
if self._declare_only == 0:
# 预注册模块级变量(AnnAssign/Assign)到 SymTab
# 解决时序问题:class Logger 的 __init__ 引用 _mbuddy 时,
# _mbuddy 的 AnnAssign 在 AST 中位于 class Logger 之后,
# 按 AST 顺序翻译时 _mbuddy 尚未注册 → lookup_var 返回 None → rhs_val is None
# 预处理先于 translate_children 注册所有模块级变量,
# 后续 translate_children 遍历到同一 AnnAssign 时 handle_module_level_var
# 通过 lookup_module_var 检测已存在并跳过(HandlesMain.py:206-209)
if ch is not None:
for ci in range(cn_count):
child: ast.AST* = ch.get(ci)
if child is None:
continue
kd_mv: int = child.kind()
if kd_mv == ast.ASTKind.AnnAssign or kd_mv == ast.ASTKind.Assign:
GenApi.handle_module_level_var(self, child)
# 创建前向声明
GenApi.forward_declare_functions(self, tree)
added: int = GenApi.translate_children(self, tree)
# 容器模块自动可见性注入(对齐 TPC _inject_auto_imports)
# TPC 在翻译前自动注入 `import _list / import _dict (+json)`,使 list/dict 内建容器类
# 在符号表中可见;TPV 用可见性机制等效替代:_list.vp/_dict.vp 已由 Phase1 注册,
# 这里只需在当前文件翻译时把容器类名标记为可见结构体,裸名注解/构造即可解析。
# 检测模式(与 TPC Phase2Translator._inject_auto_imports 一致):
# - AnnAssign 注解裸名 Name(list/dict):d: dict
# - 构造调用 func 裸名 Name(list/dict):dict(bd)
# - Subscript 的 value 裸名 Name(list/dict):list[int]
def _inject_auto_container_visibility(self, pool: memhub.MemBuddy*,
tree: ast.AST*):
"""检测 list/dict 容器使用,注入容器类可见性"""
if tree is None or tree.children is None:
return
# 用栈式缓冲区传递检测结果(跨函数参数用 4 字节 int 指针)
need_list_box: t.CPtr = stdlib.malloc(4)
need_dict_box: t.CPtr = stdlib.malloc(4)
if need_list_box is None or need_dict_box is None:
if need_list_box is not None:
stdlib.free(need_list_box)
if need_dict_box is not None:
stdlib.free(need_dict_box)
return
need_list_box[0] = 0
need_dict_box[0] = 0
self._scan_container_usage(tree, need_list_box, need_dict_box)
if need_dict_box[0] != 0:
# dict 类可见 + _dict 模块导入(构造/方法调用的 SHA1 解析)
GenApi.add_visible_struct(pool, "dict")
if self._imported_modules is None or \
GenApi.is_module_imported(self._imported_modules, "_dict") == 0:
# [FIX 2026-08-31] 破环:_dict 自身依赖含当前模块则跳过注入。
# 对齐 Phase1Main._InjectedCreatesCycle,覆盖所有 translate 路径
# (Phase1 1b / Phase2 pre-inc / PhaseA)——否则 _list/_dict 显式
# import memhub 且 memhub 用容器泛型时成 2-环,Phase A 永不收敛。
if self._ContainerInjectionCreatesCycle("_dict") == 0:
self._imported_modules = GenApi.add_imported_module(pool, self._imported_modules, "_dict")
if need_list_box[0] != 0:
GenApi.add_visible_struct(pool, "list")
if self._imported_modules is None or \
GenApi.is_module_imported(self._imported_modules, "_list") == 0:
if self._ContainerInjectionCreatesCycle("_list") == 0:
self._imported_modules = GenApi.add_imported_module(pool, self._imported_modules, "_list")
stdlib.free(need_list_box)
stdlib.free(need_dict_box)
def _ContainerInjectionCreatesCycle(self, mod_name: str) -> int:
"""注入 mod_name(_list/_dict)前检查是否成环,返回 1=成环需跳过注入。
判断被注入模块自身的 deps 是否已含当前模块名。若命中(如 _list 显式
import memhub,而 memhub 因 `__provides__: list[str]` 注解要注入 _list)
→ memhub↔_list 循环依赖 → Phase A 多遍收敛死锁(gfx.vp "无法完成翻译"
根因)。对齐 Phase1Main._InjectedCreatesCycle,但本方法走 self.ModuleSha1
查 RelPath,覆盖所有 translate 路径(Phase1 1b 全量翻译、Phase2 pre-inc/
PhaseA 都会执行 _inject_auto_container_visibility)。命中则跳过注入:
去掉环边后,_list 已因当前模块被其依赖而处于闭包,list 类仍由
add_visible_struct 可见、泛型模板已由 Phase1 注册。
"""
if mod_name is None or self.ModuleSha1 is None:
return 0
inj_sha1: str = StubMergerStore.LookupSha1ByModName(mod_name)
if inj_sha1 is None:
return 0
inj_deps: str = StubMergerStore.LookupIncludesDeps(inj_sha1)
if inj_deps is None:
return 0
# 当前模块名 = RelPath 基名(最后 '/' 或 '\\' 之后)去扩展名
rel_path: str = StubMergerStore.LookupSha1RelPath(self.ModuleSha1)
if rel_path is None:
return 0
base: str = string.strrchr(rel_path, '/')
if base is None:
base = string.strrchr(rel_path, '\\')
if base is not None:
base = base + 1
else:
base = rel_path
dot: str = string.strchr(base, '.')
nm_buf: bytes = stdlib.malloc(128)
if nm_buf is None:
return 0
if dot is not None:
nm_len: sizet = sizet(uint64(dot) - uint64(base))
if nm_len > 127:
nm_len = 127
string.strncpy(nm_buf, base, nm_len)
nm_buf[nm_len] = '\0'
else:
string.strncpy(nm_buf, base, 127)
nm_buf[127] = '\0'
# 词边界精确匹配:inj_deps 中是否有 token 与当前模块名相同
nm_len2: sizet = string.strlen(nm_buf)
d_len: sizet = string.strlen(inj_deps)
dp: sizet = 0
while dp < d_len:
ts: sizet = dp
while dp < d_len and inj_deps[dp] != ' ':
dp += 1
tl: sizet = dp - ts
if dp < d_len:
dp += 1
if tl > 0 and tl == nm_len2 and string.strncmp(inj_deps + ts, nm_buf, tl) == 0:
stdlib.free(nm_buf)
return 1
stdlib.free(nm_buf)
return 0
def _scan_container_usage(self, node: ast.AST*,
need_list_box: t.CPtr,
need_dict_box: t.CPtr):
"""递归扫描 AST 语句结构,检测 list/dict 容器使用"""
if node is None:
return
k: int = node.kind()
if k == ast.ASTKind.AnnAssign:
aa_s: ast.AnnAssign* = ast.AnnAssign*(node)
if aa_s.annotation is not None:
self._check_container_type_node(aa_s.annotation, need_list_box, need_dict_box)
elif k == ast.ASTKind.Call:
cl_s: ast.Call* = ast.Call*(node)
if cl_s.func is not None:
self._check_container_type_node(cl_s.func, need_list_box, need_dict_box)
elif k == ast.ASTKind.Subscript:
sub_s: ast.Subscript* = ast.Subscript*(node)
if sub_s.value is not None:
self._check_container_type_node(sub_s.value, need_list_box, need_dict_box)
elif k == ast.ASTKind.FunctionDef:
fd_s: ast.FunctionDef* = ast.FunctionDef*(node)
if fd_s.returns is not None:
self._check_container_type_node(fd_s.returns, need_list_box, need_dict_box)
if fd_s.args is not None:
args_s: ast.Arguments* = ast.Arguments*(fd_s.args)
if args_s.args is not None:
args_list_s: list[ast.AST*]* = args_s.args
an_s: sizet = len(args_list_s)
ai_s: sizet
for ai_s in range(an_s):
arg_s: ast.AST* = args_list_s.get(ai_s)
if arg_s is not None:
ag_s: ast.Arg* = ast.Arg*(arg_s)
if ag_s.annotation is not None:
self._check_container_type_node(ag_s.annotation, need_list_box, need_dict_box)
# `[...]`/`{}` 字面量不触发 _list/_dict 导入:字面量广泛用于编译期常量列表
# (c.Asm 的 op/inp/out CLOBBER 参数、数组数据初始化),并非 list 容器使用。
# list/dict 容器的真实使用由类型位置检测覆盖:`x: list` / `list[...]` 注解、
# `list(...)`/`dict(...)` 构造(_check_container_type_node 的 AnnAssign.annotation /
# Call.func / Subscript.value 分支)。无注解 `x = [...]` 若意图 list,会在
# translate_list_literal 阶段 fail-fast 提示 _list 未注册(需显式注解)。
# 递归语句块子节点
if node.children is not None:
ch_s: list[ast.AST*]* = node.children
n_s: sizet = len(ch_s)
for ci_s in range(n_s):
self._scan_container_usage(ch_s.get(ci_s), need_list_box, need_dict_box)
def _check_container_type_node(self, node: ast.AST*,
need_list_box: t.CPtr,
need_dict_box: t.CPtr):
"""检测类型位置节点是否为 list/dict(支持 Name / Subscript / BinOp 递归)"""
if node is None:
return
k: int = node.kind()
if k == ast.ASTKind.Name:
nm_s: ast.Name* = ast.Name*(node)
if nm_s.id is not None:
if string.strcmp(nm_s.id, "dict") == 0:
need_dict_box[0] = 1
elif string.strcmp(nm_s.id, "list") == 0:
need_list_box[0] = 1
elif k == ast.ASTKind.Subscript:
sub_s: ast.Subscript* = ast.Subscript*(node)
if sub_s.value is not None:
self._check_container_type_node(sub_s.value, need_list_box, need_dict_box)
# rawptr[list[int]] / list[AST] 等:slice 里可能含 list,需下钻
if sub_s.slice is not None:
self._check_container_type_node(sub_s.slice, need_list_box, need_dict_box)
elif k == ast.ASTKind.BinOp:
bop_s: ast.BinOp* = ast.BinOp*(node)
self._check_container_type_node(ast.binop_get_left(bop_s), need_list_box, need_dict_box)
self._check_container_type_node(ast.binop_get_right(bop_s), need_list_box, need_dict_box)
def _annotation_is_container(self, ann: ast.AST*) -> int:
"""注解是否为 list/dict 容器(Name 裸名或 Subscript list[...]/dict[...])
数组初始化(t.CArray[...] / 裸数组注解)返回 0,避免 _scan_container_usage
把数组字面量误判为 list 容器使用(FIX 2026-08-30)。
"""
while ann is not None:
ak: int = ann.kind()
if ak == ast.ASTKind.Name:
nm_c: ast.Name* = ast.Name*(ann)
if nm_c.id is not None:
if string.strcmp(nm_c.id, "list") == 0:
return 1
if string.strcmp(nm_c.id, "dict") == 0:
return 1
return 0
elif ak == ast.ASTKind.Subscript:
sub_c: ast.Subscript* = ast.Subscript*(ann)
ann = sub_c.value
else:
return 0
return 0
# ============================================================
# IR 输出
# ============================================================
def dump_ir(self, buf: bytes, size: sizet, mode: int):
"""将 LLVM IR 输出到缓冲区
mode: 0=完整, 1=stub(仅声明), 2=text(仅代码)
"""
if self.Module is None or buf is None:
return
if _mbuddy is None:
return
buf[0] = '\0'
llvmlite.LLVMModulePrint(buf, size, self.Module, _mbuddy, mode)
# ============================================================
# --traceback: startup Install() ctor injection
#
# Lives here (not in BuildPipeline) because this module already imports
# llvmlite. Calling llvmlite.* from a module without that import mangles the
# calls with the package (__init__) SHA1, which no object defines, instead of
# the defining submodule's SHA1 (link-time undefined symbol). BuildPipeline
# only decides whether to trigger the injection.
#
# Injects into the traceback module's IR:
# define void @__traceback_install_ctor() { entry: call @Install(); ret void }
# plus an appending-linkage @llvm.global_ctors so the CRT runs Install() once at
# process start (mirrors TPC BaseGen._RegisterTracebackInstallViaCtor).
# fail-fast: a pre-existing @llvm.global_ctors, or a missing Install symbol,
# aborts the build (silent degradation would leave the product without a map).
# ============================================================
# _tb_module_has_global_ctors - does the module already define @llvm.global_ctors
def _tb_module_has_global_ctors(mod: llvmlite.LLVMModule*) -> int:
if mod is None:
return 0
g: llvmlite.GlobalVariable* = mod.GlobalHead
steps: sizet = 0
while g is not None:
steps += 1
if steps > 100000:
break
if g.Name is not None and string.strcmp(g.Name, "llvm.global_ctors") == 0:
return 1
g = g.Next
return 0
# _tb_find_install_function - locate this module's own Install()
#
# Accepts "<16hex>.Install" (the usual SHA1-mangled form) or the bare name.
def _tb_find_install_function(mod: llvmlite.LLVMModule*) -> llvmlite.Function*:
if mod is None:
return None
cur: llvmlite.Function* = mod.FuncHead
steps: sizet = 0
while cur is not None:
steps += 1
if steps > 100000:
return None
nm: str = llvmlite.function_get_name(cur)
if nm is not None:
if string.strcmp(nm, "Install") == 0:
return cur
nl: sizet = llvmlite.function_get_name_len(cur)
if nl == 24 and string.strcmp(nm + 16, ".Install") == 0:
return cur
cur = llvmlite.function_get_next(cur)
return None
# InjectTracebackInstallCtor - inject startup Install() ctor into the module
#
# NOTE: FunctionPrint has no linkage field, so the ctor is emitted with default
# (external) linkage instead of TPC's 'internal'; only traceback.vp defines it,
# so there is no symbol clash.
def InjectTracebackInstallCtor(tr: rawptr[Translator]) -> int:
if tr is None or tr.Module is None:
return 0
if tr._declare_only != 0:
return 0
pool: memhub.MemBuddy* = tr.Pool
if pool is None:
VLogger.error("--traceback: 内存池未初始化,无法注入 Install 构造器", "TRACEBACK")
return 1
mod: llvmlite.LLVMModule* = tr.Module
if _tb_module_has_global_ctors(mod) != 0:
VLogger.error("--traceback: 模块内已存在 @llvm.global_ctors,无法注入 traceback 启动期构造器(不静默降级)", "TRACEBACK")
return 1
install_fn: llvmlite.Function* = _tb_find_install_function(mod)
if install_fn is None:
VLogger.error("--traceback: 在 traceback 模块内找不到 Install() 函数,无法注入启动期构造器(不静默降级)", "TRACEBACK")
return 1
# 1) ctor: entry { call <ret> @Install(); ret void }
void_ty: llvmlite.LLVMType* = llvmlite.Void(pool)
ctor: llvmlite.Function* = llvmlite.new_function(pool, "__traceback_install_ctor", void_ty)
if ctor is None:
VLogger.error("--traceback: 构造器函数分配失败", "TRACEBACK")
return 1
blk: llvmlite.BasicBlock* = llvmlite.new_basic_block(pool, "entry")
if blk is None:
VLogger.error("--traceback: 构造器基本块分配失败", "TRACEBACK")
return 1
llvmlite.function_add_block(ctor, blk)
llvmlite.module_add_function(mod, ctor)
builder: llvmlite.IRBuilder* = llvmlite.new_builder(pool, ctor)
if builder is None:
VLogger.error("--traceback: 构造器 IRBuilder 分配失败", "TRACEBACK")
return 1
llvmlite.position_at_end(builder, blk)
iname: str = llvmlite.function_get_name(install_fn)
install_ret: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(install_fn)
llvmlite.build_call(builder, iname, None, 0, install_ret, 0)
llvmlite.build_ret_void(builder)
# 2) @llvm.global_ctors = appending global [1 x {i32, void ()*, i8*}] [ ... ]
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8p_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
fnv_ty: llvmlite.LLVMType* = llvmlite.Func(pool, void_ty, None, 0)
fnp_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, fnv_ty)
f1: llvmlite.ParamNode* = llvmlite.new_param_node(pool, i32_ty)
f2: llvmlite.ParamNode* = llvmlite.new_param_node(pool, fnp_ty)
f3: llvmlite.ParamNode* = llvmlite.new_param_node(pool, i8p_ty)
if f1 is None or f2 is None or f3 is None:
VLogger.error("--traceback: global_ctors 结构体字段分配失败", "TRACEBACK")
return 1
llvmlite.paramnode_set_next(f1, f2)
llvmlite.paramnode_set_next(f2, f3)
elem_ty: llvmlite.LLVMType* = llvmlite.Struct(pool, f1, 3, None)
arr_ty: llvmlite.LLVMType* = llvmlite.Array(pool, elem_ty, 1)
if elem_ty is None or arr_ty is None:
VLogger.error("--traceback: global_ctors 类型构造失败", "TRACEBACK")
return 1
gv: llvmlite.GlobalVariable* = llvmlite.new_global_variable(pool, "llvm.global_ctors", arr_ty)
if gv is None:
VLogger.error("--traceback: @llvm.global_ctors 全局变量分配失败", "TRACEBACK")
return 1
llvmlite.global_set_linkage(gv, "appending")
gv.Initializer = "[{ i32, void ()*, i8* } { i32 65535, void ()* @__traceback_install_ctor, i8* null }]"
llvmlite.module_add_global(mod, gv)
VLogger.info("--traceback: 已注入启动期 Install() 构造器(@llvm.global_ctors)", "TRACEBACK")
return 0
# ============================================================
# Mixin - Handler 非多态基类(自 HandlesBase 迁入)
#
# 持有 Translator 回指针。ExprCallHandle 等跨模块 handler 类经
# `class X(Translator.Mixin)` 继承(TPV 支持模块限定基类继承)。
# ============================================================
novirtual class Mixin:
"""所有 Handle 的非多态基类:持有 Translator 回指针 + 共享委托方法"""
Trans: Translator | t.CPtr
def InitMixin(self, trans: Translator | t.CPtr) -> int:
"""初始化 Mixin 字段(子类 __init__ 中调用)"""
self.Trans = trans
return 0
# ============================================================
# 全局 mbuddy 指针
_mbuddy: memhub.MemBuddy*