Files
TransPyC/lib/core/LLVMCG/FuncGen.py
T
2026-09-17 14:52:37 +08:00

591 lines
40 KiB
Python
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.
from __future__ import annotations
from typing import Any
import vast as ast
import os
import re
import sys
import llvmlite.ir as ir
from lib.core.Handles.HandlesBase import CTypeInfo
from lib.core.VLogger import get_logger as _vlog
from lib.constants.config import mode as _config_mode
class FuncGenMixin:
def setup_from_symbol_table(self, SymbolTable: Any) -> None:
self.SymbolTable: Any = SymbolTable
for name, info in SymbolTable.items():
if isinstance(info, CTypeInfo):
# CTypeInfo 对象:struct/union 由 StructGen 处理,此处只处理 dict 格式
continue
if not isinstance(info, dict):
if hasattr(info, 'get'):
info = dict(info) if hasattr(info, '__iter__') else {}
else:
continue
TypeKind: str = info.get('type', '')
if TypeKind == 'struct':
ClassName: str = name
self.class_methods[ClassName] = []
self.class_members[ClassName] = []
members: dict[str, Any] = info.get('members', {})
if members:
for MemberName, MemberInfo in members.items():
if isinstance(MemberInfo, dict):
MemberType: ir.Type = self._type_str_to_llvm(MemberInfo.get('type', 'int'), MemberInfo.get('IsPtr', False))
self.class_members[ClassName].append((MemberName, MemberType))
elif isinstance(MemberInfo, CTypeInfo):
MemberType: ir.Type = self._ctype_to_llvm(MemberInfo)
if MemberType is None:
MemberType = self._type_str_to_llvm(MemberInfo.ToString(), MemberInfo.IsPtr)
self.class_members[ClassName].append((MemberName, MemberType))
self._generate_structs()
self._create_Vtable_globals()
def register_method(self, ClassName: str, MethodName: str) -> None:
if ClassName not in self.class_methods:
self.class_methods[ClassName] = []
if ClassName not in self.class_members:
self.class_members[ClassName] = []
self._generate_structs()
self._create_Vtable_globals()
# 构造函数(__new__/__init__/__before_init__)不放入 vtable,
# 避免子类与基类 vtable 大小不一致导致虚分派索引偏移
_short_name: str = MethodName.split('.')[-1] if '.' in MethodName else MethodName
if _short_name in ('__new__', '__init__', '__before_init__'):
return
if MethodName not in self.class_methods[ClassName]:
self.class_methods[ClassName].append(MethodName)
def _apply_auto_addr(self, func_name: str, args: list[ir.Value]) -> list[ir.Value]:
"""对函数参数应用自动取地址逻辑(t.CNeedPtr / t.CAutoPtr)。
在调用前对标记为 auto-addr 的参数自动取地址:
- 'need' (t.CNeedPtr): 仅对非指针值取地址(alloca + store + get pointer)
- 'always' (t.CAutoPtr): 无条件取地址
"""
modes: list[str | None] | None = self._auto_addr_params.get(func_name)
if not modes:
return args
new_args: list[ir.Value] = list(args)
for i, mode in enumerate(modes):
if i >= len(new_args) or mode is None:
continue
arg: ir.Value = new_args[i]
is_ptr: bool = isinstance(arg.type, ir.PointerType)
if mode == 'always' or (mode == 'need' and not is_ptr):
# alloca + store + get pointer
slot: ir.Value = self.builder.alloca(arg.type)
self.builder.store(arg, slot)
new_args[i] = slot
return new_args
def _adjust_args(self, args: list[ir.Value], func: ir.Function) -> list[ir.Value]:
adjusted: list[ir.Value] = []
for i, (arg, param) in enumerate(zip(args, func.args)):
if arg.type != param.type:
if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name):
# C 语言中数组参数退化为指针,不做 load 而是退化为元素指针
if isinstance(param.type, ir.ArrayType):
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}")
adjusted.append(elem_ptr)
else:
adjusted.append(self._load(arg, name=f"Load_arg_{i}"))
continue
try:
if isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType):
if isinstance(param.type.pointee, ir.IntType) and param.type.pointee.width == 8 and arg.type.width == 8:
# 当参数是 i8(字符值)而函数期望 i8*(字符串指针)时
# 为字符值分配内存,创建 null-terminated 字符串
tmp: ir.AllocaInstr = self._alloca(ir.ArrayType(ir.IntType(8), 2), name=f"char2str_arg_{i}")
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
char_ptr: ir.Value = self.builder.gep(tmp, [zero, zero], name=f"char2str_ptr_{i}")
self._store(arg, char_ptr)
null_ptr: ir.Value = self.builder.gep(tmp, [zero, ir.Constant(ir.IntType(32), 1)], name=f"char2str_null_{i}")
self._store(ir.Constant(ir.IntType(8), 0), null_ptr)
adjusted.append(char_ptr)
else:
if isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType):
# 当参数是指针而函数期望整数时,使用 ptrtoint
adjusted.append(self.builder.ptrtoint(arg, param.type, name=f"ptrtoint_arg_{i}"))
else:
if arg.type.width < 32:
arg = self.builder.zext(arg, ir.IntType(32), name=f"zext_arg_{i}")
adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}"))
elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType):
# fail-fast:指针→整数隐式转换(跨类型层级,有损)禁止,
# 须显式转换(用户隐式转换规则:同层指针可转,指针→整数不允许)。
raise TypeError(
f"调用参数类型不匹配: 指针类型 {arg.type} 不能隐式转换为"
f"整数参数 {param.type};如需转换请显式 cast")
elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType):
if isinstance(arg.type.pointee, ir.PointerType) and isinstance(param.type.pointee, ir.IntType):
Loaded: ir.Value = self._load(arg, name=f"Load_arg_{i}")
adjusted.append(Loaded)
elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, (ir.IntType, ir.FloatType, ir.DoubleType)):
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}")
if elem_ptr.type != param.type:
adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}"))
else:
adjusted.append(elem_ptr)
elif isinstance(arg.type.pointee, ir.ArrayType) and isinstance(param.type.pointee, ir.PointerType):
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
elem_ptr: ir.Value = self.builder.gep(arg, [zero, zero], name=f"array_decay_arg_{i}")
if elem_ptr.type != param.type:
adjusted.append(self.builder.bitcast(elem_ptr, param.type, name=f"cast_arg_{i}"))
else:
adjusted.append(elem_ptr)
else:
adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}"))
else:
if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name):
adjusted.append(self._load(arg, name=f"Load_arg_{i}"))
elif isinstance(arg.type.pointee, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
tmp: ir.AllocaInstr = self._alloca(param.type, name=f"temp_arg_{i}")
Loaded: ir.Value = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}")
Loaded_val: ir.Value = self._load(Loaded, name=f"Load_arg_{i}")
self._store(Loaded_val, tmp)
adjusted.append(self._load(tmp, name=f"reLoad_arg_{i}"))
else:
tmp: ir.AllocaInstr = self._alloca(param.type, name=f"temp_arg_{i}")
cast_ptr: ir.Value = self.builder.bitcast(arg, ir.PointerType(param.type), name=f"cast_arg_{i}")
Loaded_val: ir.Value = self._load(cast_ptr, name=f"Load_arg_{i}")
self._store(Loaded_val, tmp)
adjusted.append(self._load(tmp, name=f"reLoad_arg_{i}"))
elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type:
adjusted.append(self._load(arg, name=f"Load_arg_{i}"))
elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type:
tmp: ir.AllocaInstr = self._alloca(arg.type, name=f"temp_arg_{i}")
self._store(arg, tmp)
adjusted.append(tmp)
elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.IntType):
if arg.type.width < param.type.width:
# 整数扩展:使用 sext(符号扩展)以正确处理负数
adjusted.append(self.builder.sext(arg, param.type, name=f"sext_arg_{i}"))
else:
adjusted.append(self.builder.trunc(arg, param.type, name=f"trunc_arg_{i}"))
elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, (ir.FloatType, ir.DoubleType)):
if isinstance(arg.type, ir.DoubleType) and isinstance(param.type, ir.FloatType):
adjusted.append(self.builder.fptrunc(arg, param.type, name=f"fptrunc_arg_{i}"))
elif isinstance(arg.type, ir.FloatType) and isinstance(param.type, ir.DoubleType):
adjusted.append(self.builder.fpext(arg, param.type, name=f"fpext_arg_{i}"))
else:
adjusted.append(arg)
elif isinstance(arg.type, (ir.FloatType, ir.DoubleType)) and isinstance(param.type, ir.IntType):
# fail-fast:浮点→整数隐式转换(有损)禁止,须显式转换
# (用户隐式转换规则:浮点→整数不允许)。
raise TypeError(
f"调用参数类型不匹配: 浮点类型 {arg.type} 不能隐式转换为"
f"整数参数 {param.type};如需转换请显式 cast")
elif isinstance(arg.type, ir.IntType) and isinstance(param.type, (ir.FloatType, ir.DoubleType)):
adjusted.append(self.builder.sitofp(arg, param.type, name=f"sitofp_arg_{i}"))
elif isinstance(arg.type, ir.IntType) and isinstance(param.type, ir.PointerType):
# 整数转指针:inttoptr
if arg.type.width < 64:
i64_val: ir.Value = self.builder.sext(arg, ir.IntType(64), name=f"sext_arg_{i}")
adjusted.append(self.builder.inttoptr(i64_val, param.type, name=f"inttoptr_arg_{i}"))
else:
adjusted.append(self.builder.inttoptr(arg, param.type, name=f"inttoptr_arg_{i}"))
elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.IntType):
# 指针转整数:ptrtoint
i64_val: ir.Value = self.builder.ptrtoint(arg, ir.IntType(64), name=f"ptrtoint_arg_{i}")
if i64_val.type.width > param.type.width:
adjusted.append(self.builder.trunc(i64_val, param.type, name=f"trunc_arg_{i}"))
elif i64_val.type.width < param.type.width:
adjusted.append(self.builder.sext(i64_val, param.type, name=f"sext_arg_{i}"))
else:
adjusted.append(i64_val)
else:
adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}"))
except Exception: # 参数类型调整失败时使用简化回退逻辑
if isinstance(arg.type, ir.PointerType) and isinstance(param.type, (ir.IdentifiedStructType, ir.LiteralStructType, ir.ArrayType)):
if arg.type.pointee == param.type or (hasattr(arg.type.pointee, 'name') and hasattr(param.type, 'name') and arg.type.pointee.name == param.type.name):
adjusted.append(self._load(arg, name=f"Load_arg_{i}"))
else:
adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}"))
elif isinstance(arg.type, ir.PointerType) and arg.type.pointee == param.type:
adjusted.append(self._load(arg, name=f"Load_arg_{i}"))
elif isinstance(param.type, ir.PointerType) and param.type.pointee == arg.type:
tmp: ir.AllocaInstr = self._alloca(arg.type, name=f"temp_arg_{i}")
self._store(arg, tmp)
adjusted.append(tmp)
elif isinstance(arg.type, ir.PointerType) and isinstance(param.type, ir.PointerType):
# 任意指针到指针的类型转换(如 struct* -> i8*)
adjusted.append(self.builder.bitcast(arg, param.type, name=f"cast_arg_{i}"))
else:
adjusted.append(arg)
else:
adjusted.append(arg)
while len(adjusted) < len(func.args):
missing_idx: int = len(adjusted)
param: ir.Argument = func.args[missing_idx]
param_type: ir.Type = param.type if hasattr(param, 'type') else param
if isinstance(param_type, ir.PointerType):
adjusted.append(ir.Constant(param_type, None))
elif isinstance(param_type, ir.IntType):
adjusted.append(ir.Constant(param_type, 0))
elif isinstance(param_type, (ir.FloatType, ir.DoubleType)):
adjusted.append(ir.Constant(param_type, 0.0))
else:
adjusted.append(ir.Constant(ir.IntType(32), 0))
if func.type.pointee.var_arg:
for i in range(len(func.args), len(args)):
arg: ir.Value = args[i]
adjusted.append(arg)
return adjusted
def _get_member_offset(self, field_name: str, ClassName: str | None = None) -> int | None:
# 治本修复:同名类 sha1 冲突检测。
# 当 class_sha1_map[ClassName] 的 sha1 与 Gen.structs[ClassName] 的 sha1 不一致时,
# class_members[ClassName] 可能存储了错误模块的同名类成员。
# 此处检测冲突,加载正确模块的 class_members 并以 sha1 前缀全名缓存。
_ResolvedClass: str = ClassName if ClassName else ''
if ClassName:
# 统一短名解析(治本修复 2026-08-10):struct/class_members/class_vtable/
# class_parent 均以短名注册(跨模块加载 HandlesImports L1604),而调用方
# 可能传入带 sha1 前缀的全名(如 "f47f88ae6545965a.Import"),导致下方
# 查表全部 miss 返回 None → _gep_and_Load_member 静默返回 None →
# AnnAssign InitValue 为 None → 变量 alloca 未初始化 → 运行期读垃圾指针。
ClassName = self._extract_short_name(ClassName)
# rawptr[X] / t.CPtr[X] 指针包装归一:rawptr[X] 是内建裸指针类型
# (X*),非真实类——接收者注解/类型名为 'rawptr[AST]' 时字段访问
# (child.parent)应作用于内层 struct X,否则查 class_members 全 miss
# → fast-fail "属性 'parent' 在类 'rawptr[AST]' 中找不到(struct=opaque)"
# (includes/ast/base.vp _set_parent_list bootstrap 根因)。
if ClassName.startswith('rawptr[') or ClassName.startswith('t.CPtr['):
_lb_rc: int = ClassName.find('[')
if ClassName.endswith(']') and _lb_rc > 0:
_inner_rc: str = ClassName[_lb_rc + 1:-1].strip()
_short_rc: str = _inner_rc.rsplit('.', 1)[-1] if '.' in _inner_rc else _inner_rc
_hit_rc: str | None = None
if _short_rc in self.structs:
_hit_rc = _short_rc
else:
for _k_rc in self.structs:
if self._extract_short_name(_k_rc) == _short_rc:
_hit_rc = _k_rc
break
if _hit_rc:
ClassName = _hit_rc
_ResolvedClass = ClassName
_ClassSha1Map: dict[str, str] = getattr(self, 'class_sha1_map', {})
_ExpectedSha1: str | None = _ClassSha1Map.get(ClassName)
if _ExpectedSha1:
_ExistingStruct = self.structs.get(ClassName)
if isinstance(_ExistingStruct, ir.IdentifiedStructType):
_ExistingSha1: str = self._extract_struct_sha1(_ExistingStruct)
if _ExistingSha1 and _ExistingSha1 != _ExpectedSha1:
# sha1 冲突:使用全名查找 class_members
_FullKey: str = f"{_ExpectedSha1}.{ClassName}"
if _FullKey in self.class_members and self.class_members[_FullKey]:
_ResolvedClass = _FullKey
else:
# 从正确 stub 加载 class_members
if self._Trans and hasattr(self._Trans, 'ImportHandler'):
_StubName: str = f"{_ExpectedSha1}.stub.ll"
# 临时保存旧值,清除短名条目以绕过 guard,加载后恢复
_OldMembers = self.class_members.get(ClassName)
self.class_members[ClassName] = []
try:
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, _StubName, self)
except Exception:
pass
_NewMembers = self.class_members.get(ClassName)
if _NewMembers:
self.class_members[_FullKey] = _NewMembers
_ResolvedClass = _FullKey
# 恢复旧值(避免影响其他代码对短名的依赖)
if _OldMembers:
self.class_members[ClassName] = _OldMembers
else:
self.class_members.pop(ClassName, None)
has_vtable: bool = ClassName and (ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes)
base: int = 1 if has_vtable else 0
if ClassName and ClassName in self.structs:
struct_type: ir.IdentifiedStructType = self.structs[ClassName]
if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0:
if ClassName in self.class_members:
expected_fields: int = len(self.class_members[ClassName])
actual_elements: int = len(struct_type.elements)
if base > 0 and actual_elements == expected_fields:
base = 0
elif base == 0 and actual_elements == expected_fields + 1:
# 跨模块类可能未被检测为 CVTable(如 Name 继承 AST@t.CVTable),
# 但实际 struct 首元素是 vtable ptr → 需 base=1。
# 但若类有继承(class_parent 有值),多出的 1 可能是继承字段而非 vtable,
# 需检查 struct 首元素类型:i8*/i8** 为 vtable,其他为继承字段。
_first_elem = struct_type.elements[0] if actual_elements > 0 else None
_has_parent = self.class_parent.get(ClassName) is not None
_is_vtable_ptr = (isinstance(_first_elem, ir.PointerType) and
isinstance(_first_elem.pointee, ir.IntType) and _first_elem.pointee.width == 8)
if not _has_parent or _is_vtable_ptr:
base = 1
if ClassName and ClassName not in self.class_members and self._Trans and hasattr(self._Trans, 'ImportHandler'):
# 跨模块 class_members 懒加载:struct 已从 stub 加载但 class_members
# 可能尚未从 .vpi 填充(vpi/stub 就绪时序不一致),主动按类 sha1 加载。
_Sha1sForLoad: dict[str, str] = getattr(self, 'class_sha1_map', {})
for _mod_name_lz, _mod_sha1_lz in _Sha1sForLoad.items():
try:
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(
ClassName, f"{_mod_sha1_lz}.stub.ll", self)
except Exception:
continue
if ClassName in self.class_members and len(self.class_members[ClassName]) > 0:
break
if _ResolvedClass and _ResolvedClass in self.class_members:
for i, (name, _) in enumerate(self.class_members[_ResolvedClass]):
if name == field_name:
return base + i
# 继承链回退:当字段不在当前类的 class_members 中时(常见于跨模块导入
# 父类未加载,字段被填充为 __inherited_N 占位名),沿 class_parent 链向上查找。
# 子类 struct 布局为 [vtable?] + [基类字段...] + [子类字段...],
# 基类字段在子类 struct 中的起始偏移即为 base(子类),
# 因此祖先 class_members 中的索引 i 对应子类 struct 中的偏移 base + i。
if ClassName and field_name:
_parent: str | None = self.class_parent.get(ClassName)
_visited: set = {ClassName} if ClassName else set()
while _parent and _parent not in _visited:
_visited.add(_parent)
# 跳过 __inherited_N 占位条目,只在真实字段名中查找
if _parent in self.class_members:
_members: list = self.class_members[_parent]
_has_placeholder: bool = any(n.startswith('__inherited_') for n, _ in _members)
if not _has_placeholder:
for i, (name, _) in enumerate(_members):
if name == field_name:
return base + i
# 父类 class_members 未加载或含占位条目,尝试从 stub 加载真实字段
if self._Trans and hasattr(self._Trans, 'ImportHandler'):
sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {})
for mod_name, mod_sha1 in sha1_map.items():
stub_name: str = f"{mod_sha1}.stub.ll"
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(_parent, stub_name, self)
if _parent in self.class_members and not any(n.startswith('__inherited_') for n, _ in self.class_members[_parent]):
for i, (name, _) in enumerate(self.class_members[_parent]):
if name == field_name:
return base + i
break
_parent = self.class_parent.get(_parent)
short_name: str | None = ClassName.split('.')[-1] if ClassName and '.' in ClassName else None
if short_name and short_name in self.class_members:
for i, (name, _) in enumerate(self.class_members[short_name]):
if name == field_name:
return base + i
if ClassName and field_name:
if ClassName not in self.class_members or field_name not in [n for n, _ in self.class_members.get(ClassName, [])]:
if self._Trans and hasattr(self._Trans, 'ImportHandler'):
sha1_map: dict[str, str] = getattr(self, 'ModuleSha1Map', {})
for mod_name, mod_sha1 in sha1_map.items():
stub_name: str = f"{mod_sha1}.stub.ll"
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(ClassName, stub_name, self)
if ClassName in self.class_members and len(self.class_members[ClassName]) > 0:
for i, (name, _) in enumerate(self.class_members[ClassName]):
if name == field_name:
return base + i
break
if short_name:
for mod_name, mod_sha1 in sha1_map.items():
stub_name: str = f"{mod_sha1}.stub.ll"
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_name, stub_name, self)
if short_name in self.class_members and len(self.class_members[short_name]) > 0:
for i, (name, _) in enumerate(self.class_members[short_name]):
if name == field_name:
return base + i
break
if ClassName and field_name:
for cn_key in self.class_members:
if cn_key == ClassName or cn_key.endswith(f'.{ClassName}') or (short_name and (cn_key == short_name or cn_key.endswith(f'.{short_name}'))):
for i, (name, _) in enumerate(self.class_members[cn_key]):
if name == field_name:
return base + i
# REnum 变体搜索: ClassName 是 REnum(如 MetaType),成员注册在变体结构
# (MetaType_Var, MetaType_Concrete, MetaType_App)中。变体与 REnum 主结构
# 共享 max_variant_struct 布局,偏移一致(__tag 在偏移 0,字段从偏移 1 开始)
if ClassName and field_name:
variant_prefix: str = f"{ClassName}_"
for cn_key in self.class_members:
if cn_key.startswith(variant_prefix):
for i, (name, _) in enumerate(self.class_members[cn_key]):
if name == field_name:
return i
if short_name:
variant_prefix = f"{short_name}_"
for cn_key in self.class_members:
if cn_key.startswith(variant_prefix):
for i, (name, _) in enumerate(self.class_members[cn_key]):
if name == field_name:
return i
if ClassName and ClassName in self.structs:
struct_type: ir.IdentifiedStructType = self.structs[ClassName]
if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None and len(struct_type.elements) > 0:
for cn_key, members in self.class_members.items():
if cn_key == short_name or (short_name and cn_key.endswith(f'.{short_name}')):
for i, (name, _) in enumerate(members):
if name == field_name and i < len(struct_type.elements):
return i
break
else:
if short_name:
for cn_key, members in self.class_members.items():
sn: str = cn_key.split('.')[-1] if '.' in cn_key else cn_key
if sn == short_name:
for i, (name, _) in enumerate(members):
if name == field_name and i < len(struct_type.elements):
return i
break
if ClassName and field_name and ClassName not in self.class_members:
if self._Trans and hasattr(self._Trans, 'ImportHandler'):
for temp_dir_candidate in [getattr(self, '_temp_dir', None)]:
if temp_dir_candidate and os.path.isdir(temp_dir_candidate):
for pyi_file in os.listdir(temp_dir_candidate):
if pyi_file.endswith('.vpi') or pyi_file.endswith('.pyi'):
stub_name: str = pyi_file.replace('.vpi', '.stub.ll').replace('.pyi', '.stub.ll')
short_cn: str = short_name if short_name else ClassName
self._Trans.ImportHandler._TryLoadClassMembersFromPyi(short_cn, stub_name, self)
if short_cn in self.class_members and len(self.class_members[short_cn]) > 0:
for i, (name, _) in enumerate(self.class_members[short_cn]):
if name == field_name:
return base + i
break
if ClassName and ClassName in self.structs and (ClassName not in self.class_members or len(self.class_members.get(ClassName, [])) == 0):
struct_type: ir.IdentifiedStructType = self.structs[ClassName]
if isinstance(struct_type, ir.IdentifiedStructType) and struct_type.elements is not None:
if self._Trans and hasattr(self._Trans, 'ClassHandler'):
class_handler: Any = self._Trans.ClassHandler
if self._current_tree:
for node in ast.iter_child_nodes(self._current_tree):
if isinstance(node, ast.ClassDef) and (node.name == ClassName or node.name == short_name):
if node.name not in self.class_members:
self.class_members[node.name] = []
if len(self.class_members[node.name]) == 0:
class_handler._PreRegisterClassMembers(node, self)
if ClassName in self.class_members:
for i, (name, _) in enumerate(self.class_members[ClassName]):
if name == field_name:
return base + i
if short_name and short_name in self.class_members:
for i, (name, _) in enumerate(self.class_members[short_name]):
if name == field_name:
return base + i
break
# 最后回退:当继承链回退失败但 struct body 已加载时,
# 从 struct elements 数和 class_members 数推断继承字段偏移。
# 继承字段在 struct 开头(base 之后),此 fallback 仅适用于单继承字段的情况
# (如 GSListNode[T] 的 Next 字段)。子类 struct 布局:
# [vtable?] + [基类字段...] + [子类字段...]
# 当 class_members 只含子类自身字段、基类 class_members 未加载时,
# 继承字段数 = struct_elements - class_members_count,
# 若该值 == 1,则所查字段(如 Next)的偏移 = base + 0。
if ClassName and field_name:
_st_final = self.structs.get(ClassName)
if isinstance(_st_final, ir.IdentifiedStructType) and _st_final.elements is not None:
_num_elements_final: int = len(_st_final.elements)
_members_final: list = self.class_members.get(ClassName, [])
_num_members_final: int = len(_members_final)
if _num_elements_final > _num_members_final:
_num_inherited_final: int = _num_elements_final - _num_members_final
if _num_inherited_final == 1:
# 单继承字段,偏移 = base(vtable 之后第一个位置)
return base + 0
# fast-fail(治本修复 2026-08-10):字段未找到不再静默返回 None。
# 静默 None 会让调用方(_gep_and_Load_member L26-27)直接 return None,
# AnnAssign InitValue 变 None → 变量 alloca 未初始化 → 运行期读垃圾指针
# (如 HandlesImports.HandleImport 的 imp.names → 0xffffffffffffffff 崩溃)。
# 抛出编译错误,暴露 class_members/struct 的真实状态便于定位根因。
_members_diag: list = self.class_members.get(ClassName, []) if ClassName else []
_struct_diag: str = 'not-registered'
if ClassName and ClassName in self.structs:
_st_diag = self.structs[ClassName]
if isinstance(_st_diag, ir.IdentifiedStructType):
_struct_diag = f"{len(_st_diag.elements)} elems" if _st_diag.elements is not None else 'opaque'
_member_names_diag: list = [n for n, _ in _members_diag][:16]
try:
import traceback as _tb
_tb.print_stack(file=sys.stderr)
except Exception:
pass
raise KeyError(
f"[fast-fail] 属性 '{field_name}' 在类 '{ClassName}' 中找不到"
f"(class_members={len(_members_diag)} 个: {_member_names_diag}, struct={_struct_diag})"
)
def _resolve_class_for_var(self, var_name: str) -> str | None:
for ClassName in self.class_methods:
if var_name == ClassName or var_name.startswith(f"__with_{ClassName}_"):
return ClassName
if var_name in self.variables:
var: ir.Value = self.variables[var_name]
if isinstance(var.type, ir.PointerType):
for ClassName, struct_type in self.structs.items():
if var.type.pointee == struct_type:
return ClassName
if isinstance(var.type.pointee, ir.PointerType) and var.type.pointee.pointee == struct_type:
return ClassName
return None
def _infer_return_type(self, FuncName: str) -> ir.Type:
if FuncName in self.functions:
return self.functions[FuncName].type.pointee.return_type
# 也尝试混淆后的名称
mangled: str = self._mangle_func_name(FuncName)
if mangled != FuncName and mangled in self.functions:
return self.functions[mangled].type.pointee.return_type
if FuncName in self.known_return_types:
return self.known_return_types[FuncName]
if mangled != FuncName and mangled in self.known_return_types:
return self.known_return_types[mangled]
for ClassName, methods in self.class_methods.items():
for method in methods:
if FuncName == method:
return ir.VoidType()
if self._import_handler_ref:
try:
# 先用原始名称查找,再用混淆名称查找
stub_func_type: Any = self._import_handler_ref._LookupStubFuncType(FuncName, self)
if stub_func_type is None and mangled != FuncName:
stub_func_type = self._import_handler_ref._LookupStubFuncType(mangled, self)
if stub_func_type and hasattr(stub_func_type, 'return_type'):
return stub_func_type.return_type
except Exception as _e:
if _config_mode == "strict":
raise
_vlog().warning(f"查找桩函数返回类型失败: {_e}", "Exception")
return ir.IntType(32)
def _get_or_declare_func(self, name: str, func_type: ir.FunctionType) -> ir.Function:
for fname, fobj in self.functions.items():
if fname == name:
return fobj
if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname):
return fobj
func_decl: ir.Function = ir.Function(self.module, func_type, name=name)
self.functions[name] = func_decl
return func_decl
def get_or_declare_c_func(self, name: str, fallback_type: ir.FunctionType | None = None) -> ir.Function | None:
if name in self.functions:
return self.functions[name]
for fname, fobj in self.functions.items():
if re.match(r'^[0-9a-f]{16,}\.' + re.escape(name) + r'$', fname):
return fobj
stub_func_type: ir.FunctionType | None = None
if self._import_handler_ref:
try:
stub_func_type = self._import_handler_ref._LookupStubFuncType(name, self)
except Exception as _e:
if _config_mode == "strict":
raise
_vlog().warning(f"查找桩函数类型失败: {_e}", "Exception")
if stub_func_type:
func_decl: ir.Function = ir.Function(self.module, stub_func_type, name=name)
self.functions[name] = func_decl
return func_decl
if fallback_type is not None:
func_decl: ir.Function = ir.Function(self.module, fallback_type, name=name)
self.functions[name] = func_decl
return func_decl
return None