- Gen 内部 1742 处 HandlesX.func() 改 self.Gen.Y.method() 链式调用 - 数据类/常量迁移 GenTypes.vp(10 类 + CLASS_META_*/META_*/SEQ_KIND_*/FIELD_MAX 等) - 管线/保留文件经 GenApi.vp 模块级入口(48 函数带类型注解,从 Gen 方法签名自动生成) - 删除 26 个纯委托 Handles 文件,仅留 5 个实体文件(Base/Translator/Expr/ExprCall/ExprCallTable) - 修复字段分裂:TypeGenErr CurrentFile/TraceCount 链式化;CallGenBase TempDir/Cexport 真源化
1342 lines
65 KiB
Plaintext
1342 lines
65 KiB
Plaintext
import lib.core.Gen.GenTypes as GenTypes
|
||
import lib.core.Gen.Generator as Generator
|
||
import t, c
|
||
from stdint import *
|
||
import memhub
|
||
import string
|
||
import stdlib
|
||
import llvmlite
|
||
import stdio
|
||
import ast
|
||
import hashtable
|
||
import viperlib
|
||
import lib.core.CompilerFactory as CompilerFactory
|
||
import lib.core.VLogger as VLogger
|
||
|
||
|
||
# ============================================================
|
||
# StructGenMixin - 结构体注册/字段查找 Mixin(对象化 P2-2,wiki/14-oo-refactor.md)
|
||
#
|
||
# 从 HandlesStruct.vp 迁移:
|
||
# 全局状态(_struct_table/_struct_count/_g_stdlib_alloc/
|
||
# _visible_structs/_strict_visibility)→ 本类字段
|
||
# 模块级函数(register_struct/find_struct/lookup_field/...)→ 本类方法
|
||
#
|
||
# 迁移原则(与 TypeGenMixin P2-1 一致,行为零变化):
|
||
# 1. 方法保留原函数签名(含 pool 首参),仅函数体内的全局变量改为 self.字段
|
||
# 2. HandlesStruct.vp 原函数保留为"委托":本地模块级单例 _g_gen(BuildPipeline
|
||
# /main 注入)cast 成 Generator 类型后调本类方法
|
||
# 3. FieldEntry/StructEntry 类型保留在 HandlesStruct.vp(本类字段引用)
|
||
#
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整,无 vtable 开销)。
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 常量(与 HandlesStruct 保持一致)
|
||
# ============================================================
|
||
STRUCT_MAX: t.CDefine = 512
|
||
# 字段槽位上限制(与 HandlesStruct 保持一致;Generator 43 Mixin 展平 ~120 字段,
|
||
# 2026-08-16 追加78:64 截断导致第 9+ 父类字段(StmtGenMixin.DiagStmtCount 等)
|
||
# 丢失 → __init__ 写 self.DiagStmtCount "属性写入失败")
|
||
FIELD_MAX: t.CDefine = 256
|
||
FIELD_NAME_MAX: t.CDefine = 64
|
||
# 多继承(MRO)支持:单类最大父类数 / MRO 链最大长度(Generator 43 父类;
|
||
# PARENT_MAX=16 时第 17+ 父类字段丢失 → __init__ 写 self.DiagStmtCount 失败)
|
||
PARENT_MAX: t.CDefine = 64
|
||
MRO_MAX: t.CDefine = 64
|
||
|
||
|
||
# ============================================================
|
||
# StructGenMixin - 结构体注册表/字段查找/可见性
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class StructGenMixin:
|
||
"""结构体注册与查找 Mixin(状态从 HandlesStruct 全局变量迁入)"""
|
||
|
||
# --- 全局注册表(原 _struct_table/_struct_count) ---
|
||
Gen: Generator.Generator | t.CPtr
|
||
StructTable: GenTypes.StructEntry | t.CPtr # STRUCT_MAX 槽位数组
|
||
StructCount: int
|
||
|
||
# --- OOM 回收分配模式(原 _g_stdlib_alloc) ---
|
||
StdlibAlloc: int
|
||
|
||
# --- 跨模块命名空间隔离(原 _visible_structs/_strict_visibility) ---
|
||
VisibleStructs: hashtable.HashTable | t.CPtr
|
||
StrictVisibility: int
|
||
|
||
def InitStructGen(self) -> int:
|
||
"""初始化结构体 Mixin 字段(子类构造时内联调用,规避 NoVTable 继承符号不转发)"""
|
||
if self is None:
|
||
return 1
|
||
self.StructTable = None
|
||
self.StructCount = 0
|
||
self.StdlibAlloc = 0
|
||
self.VisibleStructs = None
|
||
self.StrictVisibility = 0
|
||
return 0
|
||
|
||
# ============================================================
|
||
# P2-2 迁移方法(函数体来自 HandlesStruct.vp,全局变量改 self.字段,
|
||
# 同模块函数调用改 self.方法;签名与 HandlesStruct 原函数一致)
|
||
# ============================================================
|
||
|
||
def set_stdlib_alloc(self, flag: int):
|
||
"""设置 OOM 回收分配模式:1=1b 阶段(新条目用 stdlib),0=注册阶段(用 pool)"""
|
||
self.StdlibAlloc = flag
|
||
|
||
def get_stdlib_alloc(self) -> int:
|
||
"""读取 OOM 回收分配模式(供其他 Mixin 经 HandlesStruct 委托访问,
|
||
避免跨 Mixin 直接读 self.StdlibAlloc——Mixin 方法体按自身块内索引编译)"""
|
||
return self.StdlibAlloc
|
||
|
||
def reset_visible_structs(self, pool: memhub.MemBuddy | t.CPtr, strict: int):
|
||
"""重置可见性状态(每个文件翻译前调用)
|
||
|
||
pool: 内存分配器(严格模式下创建 HashTable)
|
||
strict: 1=严格模式(用户文件),0=宽松模式(includes 文件)
|
||
"""
|
||
self.StrictVisibility = strict
|
||
if strict != 0:
|
||
# 严格模式:创建新的 HashTable 记录可见结构体
|
||
self.VisibleStructs = hashtable.HashTable(pool)
|
||
else:
|
||
# 宽松模式:全部可见,不需要 HashTable
|
||
self.VisibleStructs = None
|
||
|
||
def add_visible_struct(self, pool: memhub.MemBuddy | t.CPtr, name: str):
|
||
"""添加可见结构体名(类定义时和 from-import 时调用)"""
|
||
if name is None:
|
||
return
|
||
# 宽松模式:全部可见,无需记录
|
||
if self.StrictVisibility == 0:
|
||
return
|
||
if self.VisibleStructs is None:
|
||
return
|
||
# 已存在则跳过(HashTable.__setitem__ 会覆盖,此处提前检查避免重复分配)
|
||
if self.VisibleStructs.__contains__(name) != 0:
|
||
return
|
||
self.VisibleStructs.set_int(name, 1)
|
||
|
||
def is_struct_visible(self, name: str) -> int:
|
||
"""检查结构体是否可见,返回 1=可见 / 0=不可见"""
|
||
if self.StrictVisibility == 0:
|
||
return 1
|
||
if name is None or self.VisibleStructs is None:
|
||
return 0
|
||
return self.VisibleStructs.__contains__(name)
|
||
|
||
def init_struct_table(self, pool: memhub.MemBuddy | t.CPtr) -> int:
|
||
"""初始化结构体注册表,返回 1 成功
|
||
|
||
StdlibAlloc=1 时表体分配在 perm_pool:1a 每文件 reset 后表本体
|
||
不被回收(否则首次 register_struct 若发生在文件级 mark 之后,
|
||
reset 会把 StructTable 连根回收,全局 find_struct 悬空)。
|
||
"""
|
||
if self.StructTable is not None:
|
||
return 1
|
||
|
||
entry_size: t.CSizeT = GenTypes.StructEntry.__sizeof__()
|
||
table_pool: memhub.MemBuddy | t.CPtr = pool
|
||
if self.StdlibAlloc != 0:
|
||
table_pool = CompilerFactory.get_perm_pool()
|
||
if table_pool is None:
|
||
table_pool = pool
|
||
self.StructTable = table_pool.alloc(entry_size * STRUCT_MAX)
|
||
if self.StructTable is None:
|
||
return 0
|
||
string.memset(self.StructTable, 0, entry_size * STRUCT_MAX)
|
||
self.StructCount = 0
|
||
return 1
|
||
|
||
def _get_struct_entry(self, i: int) -> GenTypes.StructEntry | t.CPtr:
|
||
"""获取第 i 个结构体条目"""
|
||
if self.StructTable is None or i < 0 or i >= STRUCT_MAX:
|
||
return None
|
||
entry_size: t.CSizeT = GenTypes.StructEntry.__sizeof__()
|
||
addr: t.CUInt64T = t.CUInt64T(self.StructTable) + i * entry_size
|
||
return (GenTypes.StructEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||
|
||
def _get_field_entry(self, struct_entry: GenTypes.StructEntry | t.CPtr, i: int) -> GenTypes.FieldEntry | t.CPtr:
|
||
"""获取结构体中第 i 个字段条目"""
|
||
if struct_entry is None or i < 0 or i >= FIELD_MAX:
|
||
return None
|
||
field_size: t.CSizeT = GenTypes.FieldEntry.__sizeof__()
|
||
addr: t.CUInt64T = t.CUInt64T(struct_entry.Fields) + i * field_size
|
||
return (GenTypes.FieldEntry | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||
|
||
def register_struct(self, pool: memhub.MemBuddy | t.CPtr,
|
||
name: str,
|
||
struct_ty: llvmlite.LLVMType | t.CPtr,
|
||
sha1: str = None) -> GenTypes.StructEntry | t.CPtr:
|
||
"""注册结构体类型,返回 StructEntry 指针
|
||
|
||
用类型指针去重(is 比较),不用类名去重。
|
||
这样跨模块同名类可以共存,各自有独立的字段定义。
|
||
sha1 参数在注册时直接设置 ModuleSha1(避免 set_struct_sha1 找错 entry)。
|
||
"""
|
||
if self.init_struct_table(pool) == 0:
|
||
return None
|
||
|
||
# 用类型指针去重(同一类型不重复注册,支持跨模块同名类)
|
||
# 用 t.CUInt64T 指针值比较(is 比较会触发类型安全检查解引用悬空 Ty)
|
||
st_dedup: t.CUInt64T = t.CUInt64T(struct_ty)
|
||
for i in range(self.StructCount):
|
||
existing: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||
if existing is not None and existing.Ty is not None:
|
||
if t.CUInt64T(existing.Ty) == st_dedup:
|
||
return existing
|
||
|
||
if self.StructCount >= STRUCT_MAX:
|
||
fb_st: str = VLogger.fmt_buf()
|
||
if fb_st is not None:
|
||
viperlib.snprintf(fb_st, 1024, "table full, cannot register %s", name)
|
||
VLogger.error(fb_st, "STRUCT")
|
||
return None
|
||
|
||
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(self.StructCount)
|
||
if entry is None:
|
||
return None
|
||
|
||
# 分配字段数组(1b 阶段用永久池,避免 reset 回收后 Fields 悬空)
|
||
field_size: t.CSizeT = GenTypes.FieldEntry.__sizeof__()
|
||
if self.StdlibAlloc != 0:
|
||
perm_sg: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool()
|
||
if perm_sg is None:
|
||
perm_sg = pool
|
||
entry.Fields = perm_sg.alloc(field_size * FIELD_MAX)
|
||
else:
|
||
entry.Fields = pool.alloc(field_size * FIELD_MAX)
|
||
if entry.Fields is None:
|
||
return None
|
||
string.memset(entry.Fields, 0, field_size * FIELD_MAX)
|
||
|
||
# 复制类名(1b/Phase2(StdlibAlloc=1)用永久池跨 reset 存活;
|
||
# 1a(StdlibAlloc=0)用主 pool,mark1 前不回收同样存活。
|
||
# 此前 1a 用 pool、1b 用 stdlib,find_struct_by_module 的 strcmp
|
||
# 曾读悬空 Name 越界 → G3 LinkedNode.prepend 挂起根因)
|
||
name_pool: memhub.MemBuddy | t.CPtr = pool
|
||
if self.StdlibAlloc != 0:
|
||
name_pool = CompilerFactory.get_perm_pool()
|
||
if name_pool is None:
|
||
name_pool = pool
|
||
name_len: t.CSizeT = string.strlen(name)
|
||
name_buf: str = name_pool.alloc(name_len + 1)
|
||
if name_buf is not None:
|
||
string.strcpy(name_buf, name)
|
||
entry.Name = name_buf
|
||
|
||
entry.Ty = struct_ty
|
||
entry.FieldCount = 0
|
||
|
||
# 注册时直接设置 SHA1(避免 set_struct_sha1 跨模块同名时找错 entry)
|
||
# SHA1 同样按 StdlibAlloc 选分配源(跨 1a/1b 存活,防 strcmp 悬空)
|
||
if sha1 is not None:
|
||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||
sha1_buf: str = name_pool.alloc(sha1_len + 1)
|
||
if sha1_buf is not None:
|
||
string.strcpy(sha1_buf, sha1)
|
||
entry.ModuleSha1 = sha1_buf
|
||
|
||
self.StructCount += 1
|
||
return entry
|
||
|
||
def set_struct_sha1(self, pool: memhub.MemBuddy | t.CPtr,
|
||
class_name: str, sha1: str) -> int:
|
||
"""设置结构体所属模块的 SHA1,返回 1=成功 / 0=失败"""
|
||
if class_name is None or sha1 is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(class_name)
|
||
if entry is None:
|
||
return 0
|
||
# 复制 SHA1 字符串(StdlibAlloc=1 用永久池,跨 1a/1b 存活防 strcmp 悬空)
|
||
sha1_len: t.CSizeT = string.strlen(sha1)
|
||
sha1_pool: memhub.MemBuddy | t.CPtr = pool
|
||
if self.StdlibAlloc != 0:
|
||
sha1_pool = CompilerFactory.get_perm_pool()
|
||
if sha1_pool is None:
|
||
sha1_pool = pool
|
||
sha1_buf: str = sha1_pool.alloc(sha1_len + 1)
|
||
if sha1_buf is None:
|
||
return 0
|
||
string.strcpy(sha1_buf, sha1)
|
||
entry.ModuleSha1 = sha1_buf
|
||
return 1
|
||
|
||
def get_struct_sha1(self, class_name: str) -> str:
|
||
"""获取结构体所属模块的 SHA1,返回 None=无 SHA1"""
|
||
if class_name is None or self.StructTable is None:
|
||
return None
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(class_name)
|
||
if entry is None:
|
||
return None
|
||
return entry.ModuleSha1
|
||
|
||
def add_field(self, pool: memhub.MemBuddy | t.CPtr,
|
||
struct_entry: GenTypes.StructEntry | t.CPtr,
|
||
field_name: str,
|
||
field_ty: llvmlite.LLVMType | t.CPtr,
|
||
default_val: ast.AST | t.CPtr = None,
|
||
annot_class_name: str = None) -> int:
|
||
"""向结构体添加字段,返回字段索引(-1 失败)
|
||
|
||
default_val: 字段默认值 AST 节点(可选,None=无默认值)
|
||
annot_class_name: 原始类型注解的类名(可选,用于联合类型字段的方法调用解析)
|
||
"""
|
||
if struct_entry is None or field_name is None or field_ty is None:
|
||
return -1
|
||
|
||
if struct_entry.FieldCount >= FIELD_MAX:
|
||
fb_sf: str = VLogger.fmt_buf()
|
||
if fb_sf is not None:
|
||
viperlib.snprintf(fb_sf, 1024, "field table full for %s", struct_entry.Name)
|
||
VLogger.error(fb_sf, "STRUCT")
|
||
return -1
|
||
|
||
idx: int = struct_entry.FieldCount
|
||
fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(struct_entry, idx)
|
||
if fe is None:
|
||
return -1
|
||
|
||
# 复制字段名(StdlibAlloc=1 用永久池跨 reset 存活,
|
||
# 否则 lookup_field 的 strcmp(fe.Name, ...) 读悬空越界挂起,
|
||
# 与 register_struct 的 Name 悬空同根因)
|
||
fname_pool: memhub.MemBuddy | t.CPtr = pool
|
||
if self.StdlibAlloc != 0:
|
||
fname_pool = CompilerFactory.get_perm_pool()
|
||
if fname_pool is None:
|
||
fname_pool = pool
|
||
name_len: t.CSizeT = string.strlen(field_name)
|
||
name_buf: str = fname_pool.alloc(name_len + 1)
|
||
if name_buf is not None:
|
||
string.strcpy(name_buf, field_name)
|
||
fe.Name = name_buf
|
||
|
||
fe.Index = idx
|
||
# 1b 阶段(StdlibAlloc=1)字段类型/注解类名必须深拷贝到 stdlib:
|
||
# register_struct 已迁 Fields/Name/ModuleSha1/Ty(translate_class_def L2566
|
||
# DeepCopyType),但字段级 Ty/AnnotClassName 仍存 pool 指针,本文件
|
||
# reset_to(mark1) 回收后,跨文件读取(字段展平、多继承 this 调整、
|
||
# AnnotClassName 回退、_apply_struct_defaults 的 build_gep_struct 用 fe.Ty
|
||
# 作 GEP 结果类型)解引用悬空内存 → 崩溃点漂移(json/string/builtins 之间)。
|
||
if self.StdlibAlloc != 0:
|
||
dp_pool_sg: memhub.MemBuddy | t.CPtr = CompilerFactory.get_perm_pool()
|
||
if dp_pool_sg is None:
|
||
dp_pool_sg = pool
|
||
ty_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(dp_pool_sg, field_ty)
|
||
if ty_copy is not None:
|
||
fe.Ty = ty_copy
|
||
else:
|
||
fe.Ty = field_ty
|
||
if annot_class_name is not None:
|
||
annot_len: t.CSizeT = string.strlen(annot_class_name)
|
||
annot_buf: str = CompilerFactory.get_perm_pool().alloc(annot_len + 1)
|
||
if annot_buf is not None:
|
||
string.strcpy(annot_buf, annot_class_name)
|
||
fe.AnnotClassName = annot_buf
|
||
# DefaultVal:跨文件结构体构造(_translate_struct_ctor→_apply_struct_defaults)
|
||
# 在调用方文件翻译时读取字段默认值,原 pool AST 已 reset 回收 → 常量深拷贝
|
||
# 到 perm_pool(1a 每文件 reset 后 DefaultVal 同样必须跨文件存活)
|
||
fe.DefaultVal = self._deep_copy_default_ast(dp_pool_sg, default_val)
|
||
else:
|
||
fe.Ty = field_ty
|
||
fe.AnnotClassName = annot_class_name
|
||
fe.DefaultVal = default_val
|
||
|
||
struct_entry.FieldCount = idx + 1
|
||
return idx
|
||
|
||
def _deep_copy_default_ast(self, pool: memhub.MemBuddy | t.CPtr,
|
||
default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr:
|
||
"""深拷贝字段默认值 AST 到永久池(仅常量节点),跨 1b reset 存活。
|
||
|
||
字段默认值(fe.DefaultVal)除定义文件内 _generate_before_init 使用外,
|
||
跨文件结构体构造(_translate_struct_ctor → _apply_struct_defaults)会在
|
||
调用方文件翻译时读取——原 pool AST 已 reset 回收必须深拷贝。
|
||
支持 Constant(标量)与 List(列表字面量,如 t.CArray[str] = ["py", "pyw"])。
|
||
其他非常量默认值(Name/BinOp 等引用表达式)无法安全深拷贝:返回 None
|
||
(调用方 fe.DefaultVal 保持 None,仅定义文件内 _generate_before_init
|
||
仍持有原始 pool 指针,不受影响)。
|
||
"""
|
||
if default_val is None:
|
||
return None
|
||
if default_val.kind() == ast.ASTKind.List:
|
||
return self._deep_copy_list_ast(pool, default_val)
|
||
if default_val.kind() != ast.ASTKind.Constant:
|
||
return None
|
||
src_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(default_val)
|
||
dst_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(
|
||
pool.alloc(ast.Constant.__sizeof__()))
|
||
if dst_c is None:
|
||
return None
|
||
string.memset(dst_c, 0, ast.Constant.__sizeof__())
|
||
# 拷贝 vtable 指针(AST 是 @t.CVTable,kind() 虚调用依赖首字段 vptr)
|
||
vt_ptr: t.CVoid | t.CPtr = t.CVoid(
|
||
c.Deref(t.CUInt64T(default_val, t.CPtr), t.CPtr), t.CPtr)
|
||
c.DerefAs(dst_c, vt_ptr)
|
||
# 拷贝位置字段(报错定位用)
|
||
dst_c.lineno = src_c.lineno
|
||
dst_c.col_offset = src_c.col_offset
|
||
dst_c.end_lineno = src_c.end_lineno
|
||
dst_c.end_col_offset = src_c.end_col_offset
|
||
# 拷贝常量值(int/float/str/bool 由 const_kind 区分)
|
||
dst_c.const_kind = src_c.const_kind
|
||
dst_c.int_val = src_c.int_val
|
||
dst_c.float_val = src_c.float_val
|
||
if src_c.str_val is not None:
|
||
s_len: t.CSizeT = string.strlen(src_c.str_val)
|
||
s_copy: str = pool.alloc(s_len + 1)
|
||
if s_copy is not None:
|
||
string.strcpy(s_copy, src_c.str_val)
|
||
dst_c.str_val = s_copy
|
||
return (ast.AST | t.CPtr)(dst_c)
|
||
|
||
def _deep_copy_list_ast(self, pool: memhub.MemBuddy | t.CPtr,
|
||
default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr:
|
||
"""深拷贝 List 节点(列表字面量默认值)到永久池,跨 1b reset 存活。
|
||
|
||
elts 容器手动在永久池构造(list 的 __pool__ 置 None:深拷贝的 elts
|
||
只被只读访问 get/__len__/迭代,不 append,不会触发 pool 扩容)。
|
||
元素递归调用 _deep_copy_default_ast(支持 Constant 与嵌套 List)。
|
||
"""
|
||
src_l: ast.List | t.CPtr = (ast.List | t.CPtr)(default_val)
|
||
dst_l: ast.List | t.CPtr = (ast.List | t.CPtr)(
|
||
pool.alloc(ast.List.__sizeof__()))
|
||
if dst_l is None:
|
||
return None
|
||
string.memset(dst_l, 0, ast.List.__sizeof__())
|
||
# 拷贝 vtable 指针(AST 是 @t.CVTable,kind() 虚调用依赖首字段 vptr)
|
||
vt_l: t.CVoid | t.CPtr = t.CVoid(
|
||
c.Deref(t.CUInt64T(default_val, t.CPtr), t.CPtr), t.CPtr)
|
||
c.DerefAs(dst_l, vt_l)
|
||
# 拷贝位置字段与 ctx
|
||
dst_l.lineno = src_l.lineno
|
||
dst_l.col_offset = src_l.col_offset
|
||
dst_l.end_lineno = src_l.end_lineno
|
||
dst_l.end_col_offset = src_l.end_col_offset
|
||
dst_l.ctx = src_l.ctx
|
||
# 深拷贝 elts:stdlib 手动构造 list[AST | t.CPtr] 容器
|
||
src_elts_l: list[ast.AST | t.CPtr] | t.CPtr = src_l.elts
|
||
if src_elts_l is not None:
|
||
cnt_l: t.CSizeT = len(src_elts_l)
|
||
lst_copy_l: list[ast.AST | t.CPtr] | t.CPtr = (list[ast.AST | t.CPtr] | t.CPtr)(
|
||
pool.alloc(list[ast.AST | t.CPtr].__sizeof__()))
|
||
if lst_copy_l is not None:
|
||
string.memset(lst_copy_l, 0, list[ast.AST | t.CPtr].__sizeof__())
|
||
lst_copy_l.__count__ = cnt_l
|
||
lst_copy_l.__capacity__ = cnt_l
|
||
lst_copy_l.__elem_size__ = 8
|
||
lst_copy_l.__pool__ = None
|
||
data_l: t.CVoid | t.CPtr = pool.alloc(cnt_l * 8)
|
||
if data_l is not None:
|
||
string.memset(data_l, 0, cnt_l * 8)
|
||
lst_copy_l.__data__ = data_l
|
||
li_l: t.CSizeT
|
||
for li_l in range(cnt_l):
|
||
elem_src_l: ast.AST | t.CPtr = src_elts_l.get(li_l)
|
||
if elem_src_l is not None:
|
||
elem_dst_l: ast.AST | t.CPtr = self._deep_copy_default_ast(pool, elem_src_l)
|
||
if elem_dst_l is not None:
|
||
slot_l: ast.AST | t.CPtr = (ast.AST | t.CPtr)(
|
||
t.CVoid(t.CUInt64T(data_l) + li_l * 8, t.CPtr))
|
||
slot_l[0] = elem_dst_l
|
||
dst_l.elts = lst_copy_l
|
||
return (ast.AST | t.CPtr)(dst_l)
|
||
|
||
def get_struct_count(self) -> int:
|
||
"""返回当前已注册的结构体数量"""
|
||
return self.StructCount
|
||
|
||
def find_struct(self, name: str) -> GenTypes.StructEntry | t.CPtr:
|
||
"""按类名查找结构体,返回 StructEntry 或 None
|
||
|
||
支持模块限定名(如 "HT.Translator"):
|
||
第一遍精确匹配,第二遍按类名(最后一个 '.' 之后的部分)回退
|
||
"""
|
||
if name is None or self.StructTable is None:
|
||
return None
|
||
# 第一遍:精确匹配
|
||
# StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起)
|
||
if self.StructCount < 0 or self.StructCount > 200000:
|
||
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct)", "STRUCT")
|
||
stdlib.exit(1)
|
||
for i in range(self.StructCount):
|
||
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||
if entry is not None and entry.Name is not None:
|
||
if string.strcmp(entry.Name, name) == 0:
|
||
return entry
|
||
# 第二遍:类名回退(处理模块限定名 "HT.Translator" → "Translator")
|
||
dot_pos: str = string.strrchr(name, '.')
|
||
if dot_pos is not None:
|
||
class_name: str = dot_pos + 1
|
||
if class_name is not None and class_name[0] != '\0':
|
||
for i in range(self.StructCount):
|
||
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||
if entry is not None and entry.Name is not None:
|
||
if string.strcmp(entry.Name, class_name) == 0:
|
||
return entry
|
||
return None
|
||
|
||
def find_struct_by_module(self, name: str, sha1: str) -> GenTypes.StructEntry | t.CPtr:
|
||
"""按类名 + SHA1 查找结构体,返回 StructEntry 或 None
|
||
|
||
SHA1 非 None 时:精确匹配 name+sha1,未找到返回 None(不回退,避免跨模块同名找错)
|
||
SHA1 为 None 时:回退到 find_struct(name) 按类名查找第一个
|
||
"""
|
||
if name is None or self.StructTable is None:
|
||
return None
|
||
# StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起)
|
||
if self.StructCount < 0 or self.StructCount > 200000:
|
||
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_module)", "STRUCT")
|
||
stdlib.exit(1)
|
||
if sha1 is not None:
|
||
for i in range(self.StructCount):
|
||
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||
if entry is not None and entry.Name is not None:
|
||
if string.strcmp(entry.Name, name) == 0:
|
||
if entry.ModuleSha1 is not None:
|
||
if string.strcmp(entry.ModuleSha1, sha1) == 0:
|
||
return entry
|
||
# SHA1 查找失败:不回退到 find_struct(会返回跨模块同名错误 entry)
|
||
# 返回 None 让调用方创建新类型,避免 Phase B 用错误类型短路
|
||
return None
|
||
# 无 SHA1:按类名查找第一个
|
||
return self.find_struct(name)
|
||
|
||
def reset_module_methods_emitted(self, sha1: str) -> int:
|
||
"""回滚指定模块注册类的 MethodsEmitted 标志(Phase A 重试前调用)
|
||
|
||
根因(追加87):Phase A 第 1 遍翻译类方法体时 _translate_oop_methods
|
||
先置 MethodsEmitted=1(防重入)再发射方法;方法体内跨模块调用因依赖
|
||
text.ll 未生成触发 trans._deps_pending → 整文件不写盘下遍重译。但
|
||
MethodsEmitted 存于 perm_pool 分配的 StructEntry,跨 mb.reset_to(mark2)
|
||
存活 → 第 2 遍 existing 分支被 _translate_oop_methods 的
|
||
MethodsEmitted==1 防重复检查拦截 → 类方法(含 __before_init__)永不
|
||
发射 → 链接 undefined symbol(模块级函数不受此标志保护所以正常,
|
||
AssignGenMixin text.ll 空 / HandlesTranslator 有模块函数缺类方法)。
|
||
按本文件 ModuleSha1 精确回滚,不影响其他已写盘文件的 MethodsEmitted。
|
||
"""
|
||
if sha1 is None or self.StructTable is None:
|
||
return 0
|
||
if self.StructCount < 0 or self.StructCount > 200000:
|
||
VLogger.error(f"StructCount 异常: {self.StructCount} (reset_module_methods_emitted)", "STRUCT")
|
||
return 0
|
||
reset_count: int = 0
|
||
for i in range(self.StructCount):
|
||
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||
if entry is not None:
|
||
# 普通类按 ModuleSha1 匹配
|
||
if entry.ModuleSha1 is not None:
|
||
if string.strcmp(entry.ModuleSha1, sha1) == 0:
|
||
entry.MethodsEmitted = 0
|
||
reset_count += 1
|
||
continue
|
||
# 泛型特化类按触发文件 sha1 匹配:特化类 ModuleSha1 是模板 sha1
|
||
# (方法名带模板前缀),无法匹配当前作废文件。不重置则特化方法体
|
||
# 残留 MethodsEmitted=1,下遍不补译 → text.ll 只有 call 无 define
|
||
# → ld.lld undefined symbol(list[ast.ClassDef|t.CPtr].* 根因)
|
||
if entry.SpecTriggerSha1 is not None:
|
||
if string.strcmp(entry.SpecTriggerSha1, sha1) == 0:
|
||
entry.MethodsEmitted = 0
|
||
reset_count += 1
|
||
return reset_count
|
||
|
||
def find_struct_by_type(self, struct_ty: llvmlite.LLVMType | t.CPtr) -> GenTypes.StructEntry | t.CPtr:
|
||
"""按类型指针查找结构体(指针值比较),返回 StructEntry 或 None
|
||
|
||
注意: 不能用 `entry.Ty is struct_ty` 的 is 比较——TPV 编译 is 时会触发
|
||
translate_compare 的类型安全检查(is_ptr_type/TypePrint 递归打印),
|
||
对悬空 entry.Ty(1b 泛型特化类注册后被 reset 回收的 pool 指针)解引用崩溃。
|
||
改用 t.CUInt64T 纯指针值比较,不解引用任何内容。
|
||
"""
|
||
if struct_ty is None or self.StructTable is None:
|
||
return None
|
||
# StructCount 合理性守卫(内存损坏导致巨大值 → 索引循环假挂起)
|
||
if self.StructCount < 0 or self.StructCount > 200000:
|
||
VLogger.error(f"StructCount 异常: {self.StructCount} (find_struct_by_type)", "STRUCT")
|
||
stdlib.exit(1)
|
||
st_val: t.CUInt64T = t.CUInt64T(struct_ty)
|
||
for i in range(self.StructCount):
|
||
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||
if entry is not None and entry.Ty is not None:
|
||
if t.CUInt64T(entry.Ty) == st_val:
|
||
return entry
|
||
return None
|
||
|
||
def lookup_field(self, struct_ty: llvmlite.LLVMType | t.CPtr,
|
||
field_name: str) -> GenTypes.FieldEntry | t.CPtr:
|
||
"""按结构体类型和字段名查找字段信息
|
||
|
||
两遍查找策略(跨模块同名类冲突的根本修复):
|
||
第一遍: 类型指针 is 身份比较(最高优先级,类型唯一确定 entry)
|
||
第二遍: 名称回退(is 未匹配时,按类名/strstr 匹配,字段未找到时 continue)
|
||
"""
|
||
if struct_ty is None or field_name is None or self.StructTable is None:
|
||
return None
|
||
|
||
# ============================================================
|
||
# 两遍查找策略(跨模块同名类冲突的根本修复):
|
||
#
|
||
# 第一遍: 用类型指针 is 身份比较(最高优先级)
|
||
# - is 匹配唯一确定 entry,字段未找到直接返回 None
|
||
# - 规避联合类型 == BUG,且不受遍历顺序影响
|
||
#
|
||
# 第二遍: 名称回退(is 未匹配到任何 entry 时才执行)
|
||
# - 用于未注册类型或 is 不可靠的场景
|
||
# - 名称匹配但字段未找到时 continue(继续检查其他同名 entry)
|
||
# ============================================================
|
||
|
||
# 第一遍: is 身份比较(用 t.CUInt64T 指针值比较,避免 is 编译路径解引用悬空 Ty)
|
||
st_lk: t.CUInt64T = t.CUInt64T(struct_ty)
|
||
for i in range(self.StructCount):
|
||
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||
if entry is not None and entry.Ty is not None:
|
||
if t.CUInt64T(entry.Ty) == st_lk:
|
||
# is 匹配,查找字段
|
||
for fi in range(entry.FieldCount):
|
||
fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(entry, fi)
|
||
if fe is not None and fe.Name is not None:
|
||
if string.strcmp(fe.Name, field_name) == 0:
|
||
return fe
|
||
# is 匹配但字段未找到(类型唯一确定,无需继续)
|
||
return None
|
||
|
||
# 第二遍: 名称回退(is 未匹配到)
|
||
ty_name: str = self._extract_struct_name(struct_ty)
|
||
if ty_name is not None:
|
||
for i in range(self.StructCount):
|
||
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||
if entry is not None and entry.Name is not None:
|
||
matched: int = 0
|
||
if string.strcmp(entry.Name, ty_name) == 0:
|
||
matched = 1
|
||
elif string.strstr(ty_name, entry.Name) is not None:
|
||
matched = 1
|
||
if matched != 0:
|
||
# 查找字段
|
||
for fi in range(entry.FieldCount):
|
||
fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(entry, fi)
|
||
if fe is not None and fe.Name is not None:
|
||
if string.strcmp(fe.Name, field_name) == 0:
|
||
return fe
|
||
# 名称匹配但字段未找到,继续检查其他同名 entry(跨模块同名)
|
||
continue
|
||
# 所有条目都未匹配
|
||
return None
|
||
|
||
def lookup_field_by_class(self, class_name: str,
|
||
field_name: str,
|
||
sha1: str = None) -> GenTypes.FieldEntry | t.CPtr:
|
||
"""按类名和字段名查找字段信息
|
||
|
||
优先用 SHA1 匹配(跨模块同名类区分),无 SHA1 时按类名查找第一个
|
||
"""
|
||
if class_name is None or field_name is None:
|
||
return None
|
||
|
||
# 优先用 SHA1 匹配(跨模块同名类区分)
|
||
# 支持模块限定名:class_name 可能是 "HT.Translator",entry.Name 是 "Translator"
|
||
# 先精确匹配,失败后用 strrchr 提取类名部分回退匹配
|
||
if sha1 is not None:
|
||
sha1_matched: int = 0
|
||
# 计算类名回退部分("HT.Translator" → "Translator")
|
||
bare_name: str = class_name
|
||
dot_pos_lfbc: str = string.strrchr(class_name, '.')
|
||
if dot_pos_lfbc is not None:
|
||
bare_name = dot_pos_lfbc + 1
|
||
if bare_name is None or bare_name[0] == '\0':
|
||
bare_name = class_name
|
||
for i in range(self.StructCount):
|
||
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||
if entry is not None and entry.Name is not None:
|
||
# 精确匹配或类名回退匹配
|
||
name_match: int = 0
|
||
if string.strcmp(entry.Name, class_name) == 0:
|
||
name_match = 1
|
||
elif bare_name is not class_name and string.strcmp(entry.Name, bare_name) == 0:
|
||
name_match = 1
|
||
if name_match != 0:
|
||
if entry.ModuleSha1 is not None \
|
||
and string.strcmp(entry.ModuleSha1, sha1) == 0:
|
||
sha1_matched = 1
|
||
# SHA1 + 类名匹配,查找字段
|
||
for fi in range(entry.FieldCount):
|
||
fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(entry, fi)
|
||
if fe is not None and fe.Name is not None \
|
||
and string.strcmp(fe.Name, field_name) == 0:
|
||
return fe
|
||
return None
|
||
|
||
# 回退: 无 SHA1 或 SHA1 匹配失败,按类名查找第一个
|
||
entry = self.find_struct(class_name)
|
||
if entry is None:
|
||
# 诊断:目标类未注册
|
||
fb_lfbc: str = VLogger.fmt_buf()
|
||
if fb_lfbc is not None:
|
||
viperlib.snprintf(fb_lfbc, 1024,
|
||
"lookup_field_by_class: 类 '%s' 未注册 (struct_count=%d)",
|
||
class_name, self.StructCount)
|
||
VLogger.error(fb_lfbc, "STRUCT")
|
||
return None
|
||
# 先查找字段(诊断/error 之前返回,否则 error 立即退出导致查找永远失败)
|
||
for fi in range(entry.FieldCount):
|
||
fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(entry, fi)
|
||
if fe is not None and fe.Name is not None:
|
||
if string.strcmp(fe.Name, field_name) == 0:
|
||
return fe
|
||
# REnum 变体字段别名回退:REnum 类(如 LLVMType)的变体内部字段
|
||
# (Ptr.Pointee 等)不是普通字段,而是 _p1/_p2 槽位别名。此前在调用方
|
||
# (ExprGenMixin 按需过滤 L5046/L5500)回退,但本函数字段未找到的
|
||
# VLogger.error 立即 sys.exit(1),调用方回退永远执行不到("LLVMType 已注册
|
||
# 但字段 Pointee 未找到"四次依旧的根因)。此处直接查变体别名,所有调用方
|
||
# 统一受益。注意:_lookup_renum_field_alias 用 class_name 指针值比较,
|
||
# 必须传 entry.Name(register_struct 复制 + _update_renum_alias_class_ptr
|
||
# 统一后的池指针),传调用方 class_name(AnnotClassName 等不同指针)
|
||
# 恒不匹配 → 返回 -1 → 回退失效。
|
||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||
rn_cls_l: str = entry.Name
|
||
if rn_cls_l is None:
|
||
rn_cls_l = class_name
|
||
rn_is_renum_l: int = self.Gen.ClassGenEnum._is_renum_class_name(class_name)
|
||
if rn_is_renum_l == 0 and rn_cls_l is not None:
|
||
# 类名可能是模块限定名("mod.LLVMType"),REnum 表存裸名,双保险
|
||
rn_is_renum_l = self.Gen.ClassGenEnum._is_renum_class_name(rn_cls_l)
|
||
rn_alias_l: int = -1
|
||
if rn_is_renum_l != 0:
|
||
rn_alias_l = self.Gen.ClassGenEnum._lookup_renum_field_alias(
|
||
rn_cls_l, field_name)
|
||
if rn_alias_l < 1 and class_name is not rn_cls_l:
|
||
# 双保险:别名表可能仍持有旧 AST 指针(_update_renum_alias_class_ptr
|
||
# 未执行/多模块重复注册场景),用调用方 class_name 再试一次
|
||
rn_alias_l = self.Gen.ClassGenEnum._lookup_renum_field_alias(
|
||
class_name, field_name)
|
||
if rn_alias_l >= 1:
|
||
rn_fe_l: GenTypes.FieldEntry | t.CPtr = \
|
||
self.Gen.StructGen._get_field_entry(entry, rn_alias_l)
|
||
if rn_fe_l is not None and rn_fe_l.Ty is not None:
|
||
return rn_fe_l
|
||
# 诊断:找到结构体但字段确实未找到,打印字段表
|
||
# 注意:VLogger.error 会立即退出进程,字段表须在 error 之前用 warning 打印
|
||
for fi in range(entry.FieldCount):
|
||
fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(entry, fi)
|
||
if fe is not None:
|
||
fb_fn: str = VLogger.fmt_buf()
|
||
if fb_fn is not None:
|
||
if fe.Name is not None:
|
||
viperlib.snprintf(fb_fn, 1024, " 字段[%d]: '%s'", fi, fe.Name)
|
||
else:
|
||
viperlib.snprintf(fb_fn, 1024, " 字段[%d]: (null)", fi)
|
||
VLogger.warning(fb_fn, "STRUCT")
|
||
fb_fields: str = VLogger.fmt_buf()
|
||
if fb_fields is not None:
|
||
if rn_is_renum_l != 0:
|
||
# 报错友好化:REnum 类直接说明是"变体字段别名查找失败",并附
|
||
# entry.Name 与别名槽位结果,一眼可辨"别名未注册"(槽位=-1)
|
||
# 还是"class_name 指针未统一"(已注册但传错指针查不到)
|
||
viperlib.snprintf(fb_fields, 1024,
|
||
"lookup_field_by_class: 类 '%s' 是 REnum 类(FieldCount=%d),"
|
||
"变体字段 '%s' 别名查找失败(entry.Name='%s',别名槽位=%d,"
|
||
"请检查该变体字段是否已注册别名,或 class_name 指针是否统一)",
|
||
class_name, entry.FieldCount, field_name, rn_cls_l, rn_alias_l)
|
||
else:
|
||
viperlib.snprintf(fb_fields, 1024,
|
||
"lookup_field_by_class: 类 '%s' 已注册 (FieldCount=%d) 但字段 '%s' 未找到",
|
||
class_name, entry.FieldCount, field_name)
|
||
VLogger.error(fb_fields, "STRUCT")
|
||
# 诊断:找到结构体但字段未找到
|
||
return None
|
||
|
||
def get_struct_type(self, class_name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""按类名获取结构体的 LLVM 类型"""
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(class_name)
|
||
if entry is not None:
|
||
return entry.Ty
|
||
return None
|
||
|
||
def get_field_by_index(self, class_name: str,
|
||
idx: int) -> GenTypes.FieldEntry | t.CPtr:
|
||
"""按类名和字段索引获取字段信息"""
|
||
if class_name is None:
|
||
return None
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(class_name)
|
||
if entry is None:
|
||
return None
|
||
if idx < 0 or idx >= entry.FieldCount:
|
||
return None
|
||
return self._get_field_entry(entry, idx)
|
||
|
||
def struct_has_defaults(self, class_name: str) -> int:
|
||
"""检查结构体是否有任何带默认值的字段,返回 1=有 / 0=无"""
|
||
if class_name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(class_name)
|
||
if entry is None:
|
||
return 0
|
||
for fi in range(entry.FieldCount):
|
||
fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(entry, fi)
|
||
if fe is not None and fe.DefaultVal is not None:
|
||
return 1
|
||
return 0
|
||
|
||
def get_struct_type_from_value(self, val: llvmlite.Value | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
|
||
"""从 Value 的类型推断结构体类型
|
||
|
||
递归解 Ptr:支持 X|t.CPtr 联合简化产生的 Ptr(Ptr(Struct)) 对象指针
|
||
(如运算符重载中间结果 a*2.0 的 Vec3**),否则 try_operator_overload
|
||
重载识别失败回退原生运算,对指针生成非法 sub 指令(llc: invalid
|
||
operand type for instruction)。
|
||
"""
|
||
if val is None or val.Ty is None:
|
||
return None
|
||
ty: llvmlite.LLVMType | t.CPtr = val.Ty
|
||
while ty is not None:
|
||
match ty:
|
||
case llvmlite.LLVMType.Ptr(pointee):
|
||
ty = pointee
|
||
case llvmlite.LLVMType.Struct(fields, fcount, name):
|
||
return ty
|
||
case _:
|
||
return None
|
||
return None
|
||
|
||
def mark_as_union(self, name: str) -> int:
|
||
"""标记已注册的结构体为联合体,返回 1=成功 / 0=失败"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
entry.IsUnion = 1
|
||
return 1
|
||
|
||
def is_union_by_name(self, name: str) -> int:
|
||
"""按类名检查是否为联合体,返回 1=是 / 0=否"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
return entry.IsUnion
|
||
|
||
def is_union_by_type(self, struct_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""按类型指针检查是否为联合体,返回 1=是 / 0=否
|
||
|
||
先尝试类型指针 == 比较,失败时回退到名称匹配
|
||
"""
|
||
if struct_ty is None or self.StructTable is None:
|
||
return 0
|
||
ty_name: str = self._extract_struct_name(struct_ty)
|
||
st_iu: t.CUInt64T = t.CUInt64T(struct_ty)
|
||
for i in range(self.StructCount):
|
||
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||
if entry is not None and entry.Ty is not None:
|
||
matched: int = 0
|
||
if t.CUInt64T(entry.Ty) == st_iu:
|
||
matched = 1
|
||
elif ty_name is not None and entry.Name is not None:
|
||
if string.strcmp(entry.Name, ty_name) == 0:
|
||
matched = 1
|
||
elif string.strstr(ty_name, entry.Name) is not None:
|
||
matched = 1
|
||
if matched != 0:
|
||
return entry.IsUnion
|
||
return 0
|
||
|
||
def mark_as_oop(self, name: str) -> int:
|
||
"""标记已注册的结构体为 OOP,返回 1=成功 / 0=失败"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
entry.IsOOP = 1
|
||
return 1
|
||
|
||
def is_oop_by_name(self, name: str) -> int:
|
||
"""按类名检查是否为 OOP 结构体,返回 1=是 / 0=否"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
return entry.IsOOP
|
||
|
||
def mark_has_init(self, name: str) -> int:
|
||
"""标记结构体拥有 __init__ 方法,返回 1=成功 / 0=失败"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
entry.HasInit = 1
|
||
return 1
|
||
|
||
def has_init_by_name(self, name: str) -> int:
|
||
"""按类名检查是否有 __init__ 方法,返回 1=有 / 0=无"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
return entry.HasInit
|
||
|
||
def mark_has_new(self, name: str) -> int:
|
||
"""标记结构体拥有 __new__ 方法,返回 1=成功 / 0=失败"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
entry.HasNew = 1
|
||
return 1
|
||
|
||
def has_new_by_name(self, name: str) -> int:
|
||
"""按类名检查是否有 __new__ 方法,返回 1=有 / 0=无"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
return entry.HasNew
|
||
|
||
def get_class_name_by_type(self, pool: memhub.MemBuddy | t.CPtr,
|
||
struct_ty: llvmlite.LLVMType | t.CPtr) -> str:
|
||
"""按类型指针查找类名,返回类名字符串或 None"""
|
||
if struct_ty is None or self.StructTable is None:
|
||
return None
|
||
st_cn: t.CUInt64T = t.CUInt64T(struct_ty)
|
||
for i in range(self.StructCount):
|
||
entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i)
|
||
if entry is not None and entry.Ty is not None:
|
||
if t.CUInt64T(entry.Ty) == st_cn:
|
||
return entry.Name
|
||
# 回退: 类型指针比较失败时,遍历所有注册的结构体按名称匹配
|
||
# 提取 struct_ty 的 Name 字段(可能是 "SHA1.ClassName" 格式)
|
||
ty_name: str = self._extract_struct_name(struct_ty)
|
||
if ty_name is not None:
|
||
for j in range(self.StructCount):
|
||
entry2: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(j)
|
||
if entry2 is not None and entry2.Name is not None:
|
||
# 构造 "SHA1.ClassName" 格式进行比较
|
||
entry2_sha1: str = entry2.ModuleSha1
|
||
if entry2_sha1 is not None:
|
||
full_nm: str = pool.alloc(128)
|
||
if full_nm is not None:
|
||
viperlib.snprintf(full_nm, 128, "%s.%s", entry2_sha1, entry2.Name)
|
||
if string.strcmp(full_nm, ty_name) == 0:
|
||
return entry2.Name
|
||
# 也直接比较类名(struct_ty 的 Name 可能无 SHA1 前缀)
|
||
if string.strcmp(entry2.Name, ty_name) == 0:
|
||
return entry2.Name
|
||
# 最后回退: 后缀匹配("SHA1.ClassName" 尾部)——比 strstr 子串
|
||
# 匹配安全:特化名 "SHA1.GSList[Param]" 会被基础名 "GSList" 错误
|
||
# 命中(子串),导致链式方法调用 class_name 解析错(如
|
||
# func.Params.append → GSList.append 查找失败 → 兄弟 Mixin 兜底
|
||
# 误匹配 LinkedNode.append,this 前移 sizeof(LinkedNode) 写穿
|
||
# 容器前 48 字节,LLvmLiteTest Test 3 崩溃根因)。
|
||
if entry2.Name is not None and string.strlen(entry2.Name) > 0:
|
||
_tlen_cn: t.CSizeT = string.strlen(ty_name)
|
||
_nlen_cn: t.CSizeT = string.strlen(entry2.Name)
|
||
if _tlen_cn > _nlen_cn and ty_name[_tlen_cn - _nlen_cn - 1] == '.':
|
||
_tail_ok_cn: int = 1
|
||
_ti_cn: t.CSizeT
|
||
for _ti_cn in range(_nlen_cn):
|
||
if ty_name[_tlen_cn - _nlen_cn + _ti_cn] != entry2.Name[_ti_cn]:
|
||
_tail_ok_cn = 0
|
||
break
|
||
if _tail_ok_cn == 1:
|
||
return entry2.Name
|
||
return None
|
||
|
||
def _extract_struct_name(self, ty: llvmlite.LLVMType | t.CPtr) -> str:
|
||
"""从 LLVMType 提取 Struct 变体的 Name 字段,返回 None 非 Struct"""
|
||
if ty is None:
|
||
return None
|
||
match ty:
|
||
case llvmlite.LLVMType.Struct(fields, fcount, name):
|
||
return name
|
||
case _:
|
||
return None
|
||
|
||
def mark_has_vtable(self, name: str) -> int:
|
||
"""标记结构体拥有虚表,返回 1=成功 / 0=失败"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
entry.HasVTable = 1
|
||
return 1
|
||
|
||
def has_vtable_by_name(self, name: str) -> int:
|
||
"""按类名检查是否有虚表,返回 1=有 / 0=无"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
return entry.HasVTable
|
||
|
||
def mark_novtable(self, name: str) -> int:
|
||
"""标记结构体为 NoVTable,返回 1=成功 / 0=失败"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
entry.IsNoVTable = 1
|
||
return 1
|
||
|
||
def is_novtable_by_name(self, name: str) -> int:
|
||
"""按类名检查是否为 NoVTable,返回 1=是 / 0=否"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
return entry.IsNoVTable
|
||
|
||
def set_parent_name(self, name: str, parent_name: str) -> int:
|
||
"""设置结构体的父类名,返回 1=成功 / 0=失败"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
entry.ParentName = parent_name
|
||
return 1
|
||
|
||
def set_parent_names(self, pool: memhub.MemBuddy | t.CPtr,
|
||
name: str, names_ptr: t.CSizeT | t.CPtr,
|
||
count: int) -> int:
|
||
"""设置结构体的父类名数组(永久池深拷贝,跨文件永久存活)"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
if names_ptr is None or count <= 0:
|
||
entry.ParentNames = None
|
||
entry.ParentCount = 0
|
||
return 1
|
||
if count > PARENT_MAX:
|
||
count = PARENT_MAX
|
||
pn_pool: memhub.MemBuddy | t.CPtr = pool
|
||
if self.StdlibAlloc != 0:
|
||
pn_pool = CompilerFactory.get_perm_pool()
|
||
if pn_pool is None:
|
||
pn_pool = pool
|
||
arr: t.CSizeT | t.CPtr = pn_pool.alloc(8 * count)
|
||
if arr is None:
|
||
return 0
|
||
for i in range(count):
|
||
addr: t.CSizeT = names_ptr[i]
|
||
arr[i] = 0
|
||
if addr != 0:
|
||
src: str = (str | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||
if src is not None:
|
||
slen: t.CSizeT = string.strlen(src)
|
||
dup: str = pn_pool.alloc(slen + 1)
|
||
if dup is not None:
|
||
string.strcpy(dup, src)
|
||
arr[i] = t.CSizeT(dup)
|
||
entry.ParentNames = t.CSizeT(arr)
|
||
entry.ParentCount = count
|
||
return 1
|
||
|
||
def get_parent_count(self, name: str) -> int:
|
||
"""获取父类数量(0=无父类,1=单继承,>1=多继承)"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
return entry.ParentCount
|
||
|
||
def get_parent_name_at(self, name: str, idx: int) -> str:
|
||
"""获取第 idx 个父类名,越界返回 None"""
|
||
if name is None or idx < 0:
|
||
return None
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None or entry.ParentNames is None:
|
||
return None
|
||
if idx >= entry.ParentCount:
|
||
return None
|
||
parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.ParentNames, t.CPtr))
|
||
addr: t.CSizeT = parr[idx]
|
||
if addr == 0:
|
||
return None
|
||
return (str | t.CPtr)(t.CVoid(addr, t.CPtr))
|
||
|
||
def get_mro_chain(self, pool: memhub.MemBuddy | t.CPtr,
|
||
name: str) -> t.CSizeT | t.CPtr:
|
||
"""MRO 线性化类名数组(深度优先 + 声明顺序 + 去重,含自身)"""
|
||
if pool is None or name is None:
|
||
return None
|
||
arr: t.CSizeT | t.CPtr = pool.alloc(8 * (MRO_MAX + 1))
|
||
if arr is None:
|
||
return None
|
||
stack: t.CSizeT | t.CPtr = pool.alloc(8 * MRO_MAX)
|
||
if stack is None:
|
||
return None
|
||
visited: t.CSizeT | t.CPtr = pool.alloc(8 * MRO_MAX)
|
||
if visited is None:
|
||
return None
|
||
stack_count: int = 0
|
||
out_count: int = 0
|
||
visit_count: int = 0
|
||
# 初始压入自身
|
||
stack[0] = t.CSizeT(name)
|
||
stack_count = 1
|
||
while stack_count > 0:
|
||
stack_count -= 1
|
||
cur_addr: t.CSizeT = stack[stack_count]
|
||
cur: str = (str | t.CPtr)(t.CVoid(cur_addr, t.CPtr))
|
||
if cur is None:
|
||
continue
|
||
# 已访问检查(线性搜索)
|
||
dup: int = 0
|
||
for vi in range(visit_count):
|
||
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 out_count < MRO_MAX:
|
||
arr[out_count] = t.CSizeT(cur)
|
||
out_count += 1
|
||
if visit_count < MRO_MAX:
|
||
visited[visit_count] = t.CSizeT(cur)
|
||
visit_count += 1
|
||
# 父类逆序压栈(正向 range 计算逆序索引,保证声明顺序弹出)
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(cur)
|
||
if entry is not None and entry.ParentCount > 0 and entry.ParentNames is not None:
|
||
pc: int = entry.ParentCount
|
||
parr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.ParentNames, t.CPtr))
|
||
for pi2 in range(pc):
|
||
pi: int = pc - 1 - pi2
|
||
if stack_count < MRO_MAX:
|
||
stack[stack_count] = parr[pi]
|
||
stack_count += 1
|
||
# 末尾 0 结束
|
||
arr[out_count] = 0
|
||
return arr
|
||
|
||
def get_parent_name(self, name: str) -> str:
|
||
"""获取结构体的父类名,返回 None=无父类"""
|
||
if name is None:
|
||
return None
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return None
|
||
return entry.ParentName
|
||
|
||
def set_vtable_methods(self, name: str, methods: str, count: int) -> int:
|
||
"""设置虚表方法名数组,返回 1=成功 / 0=失败"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
entry.VTableMethods = methods
|
||
entry.VTableMethodCount = count
|
||
return 1
|
||
|
||
def get_vtable_method_index(self, name: str, method_name: str) -> int:
|
||
"""获取方法在虚表中的索引,返回 -1=未找到"""
|
||
if name is None or method_name is None:
|
||
return -1
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None or entry.VTableMethods is None:
|
||
return -1
|
||
# VTableMethods 字段声明为 t.CChar*,但实际存储的是 t.CSizeT 数组
|
||
# 必须转换为 t.CSizeT* 才能正确读取 8 字节指针值
|
||
methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.VTableMethods, t.CPtr))
|
||
for i in range(entry.VTableMethodCount):
|
||
mname_addr: t.CSizeT = methods_arr[i]
|
||
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:
|
||
return i
|
||
return -1
|
||
|
||
def get_vtable_method_count(self, name: str) -> int:
|
||
"""获取虚表方法数量"""
|
||
if name is None:
|
||
return 0
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return 0
|
||
return entry.VTableMethodCount
|
||
|
||
def get_vtable_method_name(self, name: str, idx: int) -> str:
|
||
"""获取虚表中第 idx 个方法名,返回 None=越界"""
|
||
if name is None or idx < 0:
|
||
return None
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None or entry.VTableMethods is None:
|
||
return None
|
||
if idx >= entry.VTableMethodCount:
|
||
return None
|
||
methods_arr: t.CSizeT | t.CPtr = (t.CSizeT | t.CPtr)(t.CVoid(entry.VTableMethods, t.CPtr))
|
||
mname_addr: t.CSizeT = methods_arr[idx]
|
||
if mname_addr == 0:
|
||
return None
|
||
return (str | t.CPtr)(t.CVoid(mname_addr, t.CPtr))
|
||
|
||
def get_field_count(self, name: str) -> int:
|
||
"""获取结构体字段数量,返回 -1=未找到"""
|
||
if name is None:
|
||
return -1
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct(name)
|
||
if entry is None:
|
||
return -1
|
||
return entry.FieldCount
|
||
|
||
def ensure_struct_def_in_module(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
ty: llvmlite.LLVMType | t.CPtr):
|
||
"""确保跨模块结构体的完整定义在当前模块中可用(供 alloca 使用)
|
||
|
||
处理两种情况:
|
||
1. Struct 值类型:需要完整定义(供 alloca 分配空间)
|
||
2. Ptr(Struct) 指针类型:需要 pointee 至少有 opaque 声明
|
||
"""
|
||
if ty is None or mod is None or pool is None:
|
||
return
|
||
# 指针类型:确保 pointee 至少有 opaque 声明
|
||
match ty:
|
||
case llvmlite.LLVMType.Ptr(pointee):
|
||
llvmlite.module_ensure_opaque_for_type(mod, pool, ty)
|
||
# 如果 pointee 是 Struct,递归复制完整定义
|
||
# (GEP 访问字段需要 sized 类型,仅 opaque 会导致 llc 报错)
|
||
if pointee is not None:
|
||
self.ensure_struct_def_in_module(pool, mod, pointee)
|
||
return
|
||
case _:
|
||
pass
|
||
# 获取结构体名称(非 Struct 类型返回 None)
|
||
sname: str = llvmlite.get_struct_name(ty)
|
||
if sname is None:
|
||
return
|
||
# 检查是否为跨模块引用(名称包含 '.')
|
||
if string.strchr(sname, 46) is None:
|
||
return # 非跨模块引用,无需处理
|
||
# 提取类名(第一个 '.' 之后的部分)
|
||
# 必须用 strchr 而非 strrchr:泛型特化名如 "list[ast.AST|t.CPtr]"
|
||
# 内部含 '.'(ast.AST),strrchr 会错误地把类名解析为 "AST|t.CPtr]"
|
||
dot_pos: str = string.strchr(sname, '.')
|
||
if dot_pos is None:
|
||
return
|
||
class_name: str = dot_pos + 1
|
||
if class_name is None or class_name[0] == '\0':
|
||
return
|
||
# 提取 SHA1(sname 到 dot_pos 之间,用 strlen 避免指针减法)
|
||
total_len: t.CSizeT = string.strlen(sname)
|
||
class_name_len: t.CSizeT = string.strlen(class_name)
|
||
sha1_len: t.CSizeT = total_len - class_name_len - 1
|
||
sha1_buf: str = pool.alloc(32)
|
||
if sha1_buf is None:
|
||
return
|
||
# 32 字节缓冲:strncpy 不截断,前缀超过 31 字符会越界写 + 手动 NUL 再越界
|
||
sha1_cp: t.CSizeT = sha1_len
|
||
if sha1_cp > 31:
|
||
sha1_cp = 31
|
||
string.strncpy(sha1_buf, sname, sha1_cp)
|
||
sha1_buf[sha1_cp] = '\0'
|
||
# 按类名 + SHA1 查找结构体定义
|
||
entry: GenTypes.StructEntry | t.CPtr = self.find_struct_by_module(class_name, sha1_buf)
|
||
if entry is None:
|
||
# 回退到按类名查找(可能找到不同模块的同名类,但总比没有好)
|
||
entry = self.find_struct(class_name)
|
||
if entry is None:
|
||
return
|
||
if entry.Ty is None:
|
||
return
|
||
# 将完整定义添加到当前模块(会替换已存在的 opaque 声明)
|
||
llvmlite.module_add_named_type(mod, pool, entry.Ty)
|
||
# 递归扫描字段类型,确保值类型子结构体(如 WIN32_FIND_DATAA 中的 FILETIME)
|
||
# 也有完整定义。指针类型字段只需 opaque 声明(已由 module_ensure_opaque_for_type 处理)。
|
||
self._ensure_field_types_in_module(pool, mod, entry.Ty)
|
||
|
||
def _ensure_field_types_in_module(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
ty: llvmlite.LLVMType | t.CPtr):
|
||
"""递归扫描类型树,确保值类型子结构体有完整定义"""
|
||
if ty is None or mod is None or pool is None:
|
||
return
|
||
# 嵌套 match 遍历类型树
|
||
match ty:
|
||
case llvmlite.LLVMType.Struct(fields, fcount, sname):
|
||
# 遍历字段链表
|
||
if fields is not None:
|
||
fld: llvmlite.ParamNode | t.CPtr = fields
|
||
cnt_ef: t.CInt = 0
|
||
while fld is not None:
|
||
# 步数守卫:字段链表成环(内存损坏)导致无限遍历挂起
|
||
# (G3 LinkedNode.prepend 挂起候选),超限立即报错终止
|
||
cnt_ef += 1
|
||
if cnt_ef > 100000:
|
||
VLogger.error(
|
||
"字段链表疑似成环(_ensure_field_types_in_module),强制终止",
|
||
"STRUCT")
|
||
stdlib.exit(1)
|
||
if fld.Ty is not None:
|
||
# 值类型子结构体(如 FILETIME)需要完整定义
|
||
match fld.Ty:
|
||
case llvmlite.LLVMType.Struct(f2, fc2, n2):
|
||
self.ensure_struct_def_in_module(pool, mod, fld.Ty)
|
||
case _:
|
||
pass
|
||
self._ensure_field_types_in_module(pool, mod, fld.Ty)
|
||
fld = fld.Next
|
||
case llvmlite.LLVMType.Ptr(pointee):
|
||
# 指针类型:pointee 只需 opaque 声明,不需要完整定义
|
||
# 但如果 pointee 是 Struct,确保 opaque 声明存在
|
||
if pointee is not None:
|
||
llvmlite.module_ensure_opaque_for_type(mod, pool, ty)
|
||
case llvmlite.LLVMType.Array(elem_ty, acount):
|
||
# 数组类型:元素如果是值类型结构体,需要完整定义
|
||
# (如 zhuff_decode_tree = {MemManager*, [576 x zhuff_decode_node],
|
||
# i32, i32}——Array 元素 node 只递归字段不发射定义 → llc "use of
|
||
# undefined type named '...zhuff_decode_node'",ZlibTest 根因)
|
||
if elem_ty is not None:
|
||
match elem_ty:
|
||
case llvmlite.LLVMType.Struct(_, _, _):
|
||
self.ensure_struct_def_in_module(pool, mod, elem_ty)
|
||
case _:
|
||
pass
|
||
self._ensure_field_types_in_module(pool, mod, elem_ty)
|
||
case _:
|
||
pass
|
||
|
||
def get_field_name_ptr(self, fe: GenTypes.FieldEntry | t.CPtr) -> str:
|
||
"""获取 FieldEntry 的字段名,返回 None=未设置"""
|
||
if fe is None:
|
||
return None
|
||
return fe.Name
|
||
|
||
def get_field_type_ptr(self, fe: GenTypes.FieldEntry | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
|
||
"""获取 FieldEntry 的字段类型,返回 None=未设置"""
|
||
if fe is None:
|
||
return None
|
||
return fe.Ty
|
||
|
||
def get_field_default_ptr(self, fe: GenTypes.FieldEntry | t.CPtr) -> ast.AST | t.CPtr:
|
||
"""获取 FieldEntry 的默认值 AST 节点,返回 None=无默认值"""
|
||
if fe is None:
|
||
return None
|
||
return fe.DefaultVal
|
||
|
||
def get_field_annot_class_name(self, fe: GenTypes.FieldEntry | t.CPtr) -> str:
|
||
"""获取 FieldEntry 的原始类型注解类名,返回 None=未设置"""
|
||
if fe is None:
|
||
return None
|
||
return fe.AnnotClassName
|