657 lines
34 KiB
Python
657 lines
34 KiB
Python
from __future__ import annotations
|
||
from typing import Any
|
||
import ast
|
||
import os
|
||
import llvmlite.ir as ir
|
||
from lib.includes import t as _t
|
||
from lib.includes.t import CTypeRegistry
|
||
from lib.core.Handles.HandlesBase import CTypeInfo as _CTypeInfo, BuiltinTypeMap
|
||
|
||
|
||
class VaArgInstruction(ir.Instruction):
|
||
def descr(self, buf: list[str]) -> None:
|
||
ptr: ir.Value = self.operands[0]
|
||
buf.append("va_arg {0} {1}, {2}\n".format(
|
||
ptr.type, ptr.get_reference(), self.type))
|
||
|
||
|
||
class BaseGenMixin:
|
||
|
||
@staticmethod
|
||
def _parse_triple(triple: str | None) -> dict[str, bool | int]:
|
||
"""解析目标三元组,返回平台信息字典"""
|
||
info: dict[str, bool | int] = {
|
||
'is_windows': False, 'is_linux': False, 'is_macos': False,
|
||
'is_x86_64': False, 'is_arm64': False, 'is_32bit': False,
|
||
'ptr_size': 8, 'long_size': 8, 'wchar_t_size': 32,
|
||
}
|
||
if not triple:
|
||
return info
|
||
triple_lower: str = triple.lower()
|
||
# 检测操作系统
|
||
if 'windows' in triple_lower or 'win32' in triple_lower or 'mingw' in triple_lower or 'msvc' in triple_lower or 'cygwin' in triple_lower:
|
||
info['is_windows'] = True
|
||
# Windows LLP64: long = 32 位, wchar_t = 16 位
|
||
info['long_size'] = 32
|
||
info['wchar_t_size'] = 16
|
||
elif 'linux' in triple_lower:
|
||
info['is_linux'] = True
|
||
elif 'darwin' in triple_lower or 'macos' in triple_lower or 'apple' in triple_lower:
|
||
info['is_macos'] = True
|
||
# 检测架构
|
||
if 'x86_64' in triple_lower or 'amd64' in triple_lower or 'x64' in triple_lower:
|
||
info['is_x86_64'] = True
|
||
elif 'aarch64' in triple_lower or 'arm64' in triple_lower:
|
||
info['is_arm64'] = True
|
||
elif 'i386' in triple_lower or 'i686' in triple_lower or 'arm' in triple_lower:
|
||
info['is_32bit'] = True
|
||
info['ptr_size'] = 4
|
||
info['long_size'] = 32
|
||
if info['is_windows']:
|
||
info['wchar_t_size'] = 16
|
||
else:
|
||
info['wchar_t_size'] = 32
|
||
return info
|
||
|
||
def __init__(self, triple: str | None = None, datalayout: str | None = None) -> None:
|
||
self.module: ir.Module = ir.Module(name="transpyc_module")
|
||
if triple:
|
||
self.module.triple = triple
|
||
else:
|
||
self.module.triple = "x86_64-none-elf"
|
||
if datalayout:
|
||
self.module.data_layout = datalayout
|
||
else:
|
||
self.module.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||
|
||
# 解析目标平台信息
|
||
self._platform_info: dict[str, bool | int] = self._parse_triple(self.module.triple)
|
||
self.ptr_size: int = self._platform_info['ptr_size']
|
||
# 根据目标平台配置 t 模块中的平台相关类型大小
|
||
_t.configure_platform(self.module.triple)
|
||
self.builder: ir.IRBuilder | None = None
|
||
self.func: ir.Function | None = None
|
||
self.functions: dict[str, ir.Function] = {}
|
||
self.variables: dict[str, ir.Value | None] = {}
|
||
self._direct_values: dict[str, ir.Value] = {}
|
||
self._reg_values: dict[str, ir.Value] = {}
|
||
self.var_signedness: dict[str, bool] = {}
|
||
self._unsigned_results: set[int] = {}
|
||
self.string_const_counter: int = 0
|
||
self.Vtables: dict[str, ir.GlobalVariable] = {}
|
||
self.class_methods: dict[str, list[str]] = {}
|
||
self.class_members: dict[str, list[tuple[str, ir.Type]]] = {}
|
||
self.class_member_defaults: dict[str, dict[str, Any]] = {}
|
||
self.class_member_signeds: dict[str, dict[str, bool]] = {}
|
||
self.class_member_bitfields: dict[str, dict[str, int]] = {}
|
||
self.class_member_byteorders: dict[str, dict[str, str]] = {}
|
||
self.local_var_byteorders: dict[str, str] = {}
|
||
self.class_member_element_class: dict[str, dict[str, str]] = {}
|
||
self.class_member_bitoffsets: dict[str, dict[str, int]] = {}
|
||
self.structs: dict[str, ir.IdentifiedStructType] = {}
|
||
self.typedef_int_widths: dict[str, int] = {} # typedef名称 -> 底层整数位宽 (如 'UINT' -> 32, 'BYTE' -> 8)
|
||
self._cross_module_vtable_classes: set[str] = set()
|
||
self._cross_module_novtable: set[str] = set()
|
||
self.class_vtable: set[str] = set()
|
||
self._class_graph: dict[str, Any] = {}
|
||
self.class_parent: dict[str, str] = {}
|
||
# Store member annotations for deferred type resolution (cross-module class references)
|
||
self.class_member_annotations: dict[str, dict[str, Any]] = {}
|
||
self.loop_break_targets: list[ir.Block] = []
|
||
self.loop_continue_targets: list[ir.Block] = []
|
||
self.eh_jmp_buf_stack: list[ir.Value] = []
|
||
self.eh_except_block_stack: list[ir.Block] = []
|
||
self.eh_finally_stack: list[Any] = []
|
||
self.global_vars: set[str] = set()
|
||
self.nonlocal_params: dict[str, Any] = {}
|
||
self._variable_scope_stack: list[dict[str, Any]] = [] # Stack of outer scope variables for nested function nonlocal lookup
|
||
self.var_struct_class: dict[str, str] = {}
|
||
self.var_ptr_element: dict[str, bool] = {}
|
||
# 全局变量的指针元素标志(持久,不受函数重置影响)
|
||
# 用于全局变量 _argv: bytes | t.CPtr 等,使 _argv[index] 使用 8 字节指针步长
|
||
self.global_var_ptr_element: dict[str, bool] = {}
|
||
self.class_provides: dict[str, list[str]] = {}
|
||
self.class_requires: dict[str, list[str]] = {}
|
||
self.class_require_must: dict[str, list[str]] = {}
|
||
# 编译期 with 上下文栈:记录当前嵌套 with 链中所有可用的 provides 字段名
|
||
# 用于 __require_must__ 的纯编译期静态可达性检查
|
||
self._with_provides_stack: list[list[str]] = []
|
||
# 函数参数自动取地址模式: func_name -> [None, None, 'need', 'always', ...]
|
||
# 'need': t.CNeedPtr — 仅对非指针值取地址
|
||
# 'always': t.CAutoPtr — 无条件取地址
|
||
self._auto_addr_params: dict[str, list[str | None]] = {}
|
||
self.global_struct_class: dict[str, str] = {}
|
||
self.var_type_info: dict[str, Any] = {}
|
||
self.var_const_flags: dict[str, bool] = {}
|
||
self._current_source_file: str | None = None
|
||
self._current_source_lines: list[str] = []
|
||
self._ns_cache: dict[str, str] = {}
|
||
self._type_cache: dict[tuple[str, bool], ir.Type] = {}
|
||
self._typedef_cache: dict[str, Any] = {}
|
||
self._func_sig_cache: dict[str, Any] = {}
|
||
self.var_type_assignments: dict[str, Any] = {}
|
||
self._temp_struct_ptrs: list[ir.Value] = []
|
||
self._stop_iter_flag_param: ir.Value | None = None
|
||
self._local_heap_ptrs: list[tuple[ir.Value, str, str | None]] = []
|
||
self._var_to_heap_ptr: dict[str, ir.Value] = {}
|
||
self.known_return_types: dict[str, ir.Type] = {}
|
||
self._current_lineno: int = 0
|
||
self._current_node_info: str = ""
|
||
self.module_sha1: str | None = None
|
||
self.ModuleSha1Map: dict[str, str] = {}
|
||
self._temp_dir: str | None = None
|
||
self._export_funcs: set[str] = set()
|
||
self._export_extern_funcs: dict[str, str] = {}
|
||
self._current_module_func_names: set[str] = set()
|
||
# __doc__ 魔法字符串注册表:symbol_name -> docstring 文本(None 表示空/优化剥离)
|
||
self._doc_strings: dict[str, str | None] = {}
|
||
self.class_packed: set[str] = set()
|
||
self._define_constants: dict[str, int] = {}
|
||
# 以下属性原先在外部懒注入,此处显式初始化以避免 hasattr/getattr 动态反射
|
||
self._struct_sha1_map: dict[str, str] = {}
|
||
self.SymbolTable: Any = None
|
||
self._Trans: Any = None
|
||
self.class_sha1_map: dict[str, str] = {}
|
||
# 以下属性原先懒注入,此处显式初始化以消除 hasattr/getattr 动态反射
|
||
self._import_handler_ref: Any = None
|
||
self._classes_in_progress: set[str] = set()
|
||
# 字段收集期间添加当前类名,阻止 CollectAnnAssignMember 触发的嵌套
|
||
# _generate_structs 用不完整 class_members 调用 set_body(set_body 只能调用一次)
|
||
# 用集合而非单值,因为嵌套特化类 _EmitClassLlvm 会清除单值,导致外层类被错误设置 body
|
||
self._collecting_members_set: set[str] = set()
|
||
self._last_var_name: str | None = None
|
||
self._variadic_info: dict | None = None
|
||
self._vtable_copy_counter: int = 0
|
||
self._decorated_funcs: dict = {}
|
||
self._current_tree: Any = None
|
||
self._DefineConstants: dict = {}
|
||
self._all_define_constants: dict = {}
|
||
pi: dict[str, bool | int] = self._platform_info
|
||
# 根据目标平台设置宏(声明式,从三元组推导)
|
||
if pi['is_windows']:
|
||
self._define_constants['_WIN32'] = 1
|
||
if not pi['is_32bit']:
|
||
self._define_constants['_WIN64'] = 1
|
||
self._define_constants['WIN64'] = 1
|
||
self._define_constants['WIN32'] = 1
|
||
if pi['is_linux']:
|
||
self._define_constants['__linux__'] = 1
|
||
if pi['is_macos']:
|
||
self._define_constants['__APPLE__'] = 1
|
||
self._define_constants['__MACH__'] = 1
|
||
if pi['is_x86_64']:
|
||
self._define_constants['__x86_64__'] = 1
|
||
self._define_constants['__x86_64'] = 1
|
||
self._define_constants['_M_X64'] = 1
|
||
elif pi['is_arm64']:
|
||
self._define_constants['__aarch64__'] = 1
|
||
self._define_constants['_M_ARM64'] = 1
|
||
if not pi['is_32bit'] and pi['is_linux']:
|
||
self._define_constants['__LP64__'] = 1
|
||
elif pi['is_32bit']:
|
||
self._define_constants['_ILP32'] = 1
|
||
self._define_constants['SIZEOF_VOID_P'] = pi['ptr_size']
|
||
self._define_constants['__SIZEOF_POINTER__'] = pi['ptr_size']
|
||
|
||
def find_struct_by_pointee(self, pointee: ir.Type) -> tuple[str, ir.IdentifiedStructType] | None:
|
||
"""根据 pointee 类型查找匹配的结构体,返回 (class_name, struct_type) 或 None"""
|
||
for class_name, struct_type in self.structs.items():
|
||
if pointee == struct_type:
|
||
return (class_name, struct_type)
|
||
return None
|
||
|
||
@staticmethod
|
||
def _extract_short_name(name: str) -> str:
|
||
"""从结构体类型名中提取短名(去掉 sha1 前缀)。
|
||
如 "6bc91356c652f8ca.Function" → "Function"
|
||
如 "Function" → "Function"(无 sha1 前缀时原样返回)
|
||
"""
|
||
if '.' in name:
|
||
prefix: str = name.split('.', 1)[0]
|
||
if len(prefix) == 16 and all(c in '0123456789abcdef' for c in prefix):
|
||
return name.split('.', 1)[1]
|
||
return name
|
||
|
||
@staticmethod
|
||
def _extract_struct_sha1(st: ir.IdentifiedStructType) -> str:
|
||
"""从 IdentifiedStructType 的 name 中提取 sha1 前缀(16 位十六进制)。
|
||
返回空字符串表示无 sha1 前缀。用于同名类冲突检测。
|
||
"""
|
||
if not isinstance(st, ir.IdentifiedStructType):
|
||
return ''
|
||
try:
|
||
name: str = st.name
|
||
except (AssertionError, AttributeError):
|
||
return ''
|
||
if '.' in name:
|
||
prefix: str = name.split('.', 1)[0]
|
||
if len(prefix) == 16 and all(c in '0123456789abcdef' for c in prefix):
|
||
return prefix
|
||
return ''
|
||
|
||
def _get_or_create_struct(self, name: str, source_sha1: str | None = None, packed: bool = False) -> ir.IdentifiedStructType:
|
||
clean_name: str = name.replace(' *', '').replace('*', '').replace(' ', '_').replace('const', 'const_').replace('volatile', 'volatile_')
|
||
# 如果名称包含模块前缀(如 "a9fa0f6200c09e65.zbit_writer"),
|
||
# 先尝试用短名称(如 "zbit_writer")查找已注册的 struct,
|
||
# 避免为同一 struct 创建多个不同的类型对象导致跨模块引用类型不一致
|
||
if '.' in clean_name and clean_name not in self.structs:
|
||
parts: list[str] = clean_name.split('.', 1)
|
||
if len(parts[0]) == 16 and all(c in '0123456789abcdef' for c in parts[0]):
|
||
short_name: str = parts[1]
|
||
if short_name in self.structs:
|
||
existing_short: ir.IdentifiedStructType = self.structs[short_name]
|
||
# 治本修复:同名类 sha1 冲突检测。
|
||
# 当请求的 sha1 前缀与现有 struct 的 sha1 前缀不一致时
|
||
# (如 stmts.py:Module 与 __module.py:Module 同名冲突),
|
||
# 不能复用已有 struct(set_body 已锁定为错误布局),
|
||
# 需创建独立 struct 并以 sha1 前缀全名存储。
|
||
_existing_sha1: str = self._extract_struct_sha1(existing_short)
|
||
if _existing_sha1 and _existing_sha1 != parts[0]:
|
||
if clean_name in self.structs:
|
||
return self.structs[clean_name]
|
||
st_new: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=clean_name, packed=packed)
|
||
self.structs[clean_name] = st_new
|
||
return st_new
|
||
return existing_short
|
||
# 优先解析 typedef 整数类型(如 INT/UINT/BYTE),避免将其注册为 opaque struct。
|
||
# 必须在 `if clean_name in self.structs` 缓存检查之前执行,
|
||
# 否则首次调用(SymbolTable 未就绪时)会将 typedef 名缓存为 opaque struct,
|
||
# 后续调用即使 SymbolTable 就绪也只会返回缓存的错误类型。
|
||
# 此修复同时解决两个问题:
|
||
# 1. alloca unsized type:变量声明 `argc: INT = 6` 不再生成 `alloca %"...INT"`
|
||
# 2. 下标访问:FindStructNameInAnnotation 不再匹配 typedef 名(因不在 Gen.structs)
|
||
td_width: int | None = self._resolve_typedef_int_width(clean_name)
|
||
if td_width is not None:
|
||
if td_width > 0:
|
||
self.typedef_int_widths[clean_name] = td_width
|
||
return ir.IntType(td_width)
|
||
# td_width == 0: 特殊 typedef 名称(str/bytes/list 等),返回 i8
|
||
self.typedef_int_widths[clean_name] = 0
|
||
return ir.IntType(8)
|
||
if clean_name in self.structs:
|
||
existing: ir.IdentifiedStructType = self.structs[clean_name]
|
||
# 治本修复:同名类 sha1 冲突检测(短名调用路径)。
|
||
# 当 source_sha1 与现有 struct 的 sha1 前缀不一致时(跨模块同名类冲突),
|
||
# 不能复用已有 struct(set_body 已锁定为错误布局),
|
||
# 需创建独立 struct 并以 sha1 前缀全名存储,不覆盖短名条目。
|
||
if source_sha1:
|
||
_existing_sha1: str = self._extract_struct_sha1(existing)
|
||
if _existing_sha1 and _existing_sha1 != source_sha1:
|
||
full_key: str = f"{source_sha1}.{clean_name}"
|
||
if full_key in self.structs:
|
||
st_full: ir.IdentifiedStructType = self.structs[full_key]
|
||
if packed and isinstance(st_full, ir.IdentifiedStructType) and not st_full.packed:
|
||
st_full.packed = True
|
||
return st_full
|
||
ns_name: str = f"{source_sha1}.{clean_name}"
|
||
st_new: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed)
|
||
self.structs[full_key] = st_new
|
||
return st_new
|
||
if packed and isinstance(existing, ir.IdentifiedStructType) and not existing.packed:
|
||
existing.packed = True
|
||
return existing
|
||
if clean_name in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum', 'Void', 'void'}:
|
||
return ir.IntType(8)
|
||
if self.SymbolTable:
|
||
Entry: _CTypeInfo | None = self.SymbolTable.lookup(clean_name)
|
||
if Entry and Entry.IsTypedef:
|
||
resolved_str: str = self._resolve_typedef(clean_name)
|
||
if resolved_str != clean_name:
|
||
return self._type_str_to_llvm(resolved_str)
|
||
if Entry.BaseType:
|
||
if not isinstance(Entry.BaseType, (_t._CTypedef,)) or Entry.PtrCount > 0:
|
||
resolved: str = self._resolve_ctype_to_str(Entry)
|
||
if resolved:
|
||
return self._type_str_to_llvm(resolved)
|
||
if Entry and Entry.IsRenum:
|
||
if clean_name in self.structs:
|
||
return self.structs[clean_name]
|
||
# REnum 结构体尚未创建时不能 fall through 到 IsEnum(会返回 i32),
|
||
# 需要继续到下方正常结构体创建路径,创建 opaque 结构体。
|
||
# 这对自引用 REnum(如 LLVMType 包含 LLVMType*)至关重要:
|
||
# _parse_llvm_type 先通过此路径创建 opaque 结构体,_TryLoadStructFromStub 再 set_body。
|
||
elif Entry and Entry.IsEnum and clean_name not in self.class_methods:
|
||
return ir.IntType(32)
|
||
if Entry and Entry.IsExceptionClass:
|
||
return ir.IntType(32)
|
||
if Entry and Entry.IsFunction:
|
||
return ir.PointerType(ir.IntType(8))
|
||
if Entry and Entry.IsVariable:
|
||
return ir.PointerType(ir.IntType(8))
|
||
if Entry and Entry.BaseType:
|
||
if isinstance(Entry.BaseType, type) and issubclass(Entry.BaseType, _t.CEnum):
|
||
return ir.IntType(32)
|
||
if Entry.BaseType is _t.CEnum:
|
||
return ir.IntType(32)
|
||
ns_name: str
|
||
if source_sha1:
|
||
ns_name = f"{source_sha1}.{clean_name}"
|
||
elif clean_name in self._struct_sha1_map:
|
||
ns_name = f"{self._struct_sha1_map[clean_name]}.{clean_name}"
|
||
else:
|
||
ns_name = self._mangle_name(clean_name)
|
||
st: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, name=ns_name, packed=packed)
|
||
self.structs[clean_name] = st
|
||
# 尝试解析 typedef 的底层整数位宽
|
||
width: int | None = self._resolve_typedef_int_width(clean_name)
|
||
if width is not None:
|
||
self.typedef_int_widths[clean_name] = width
|
||
return st
|
||
|
||
def _resolve_typedef_int_width(self, name: str) -> int | None:
|
||
"""解析 typedef 名称的底层整数位宽
|
||
|
||
通过 CTypeRegistry 和 BuiltinTypeMap 动态解析,
|
||
替代硬编码的 TYPEDEF_NAMES 映射表。
|
||
返回 int 位宽或 None(无法解析)。
|
||
"""
|
||
# 1. 先查 BuiltinTypeMap(覆盖 BYTEPTR 等指针别名)
|
||
bm: Any = BuiltinTypeMap.Get(name)
|
||
if bm:
|
||
ctype_cls: Any
|
||
ptr_count: int
|
||
ctype_cls, ptr_count = bm
|
||
if ptr_count > 0:
|
||
return None # 指针类型,不是整数 typedef
|
||
llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
||
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
|
||
return int(llvm_str[1:])
|
||
|
||
# 2. 再查 SymbolTable(用户定义的 typedef)
|
||
if self.SymbolTable:
|
||
Entry: _CTypeInfo | None = self.SymbolTable.lookup(name)
|
||
if Entry and Entry.IsTypedef:
|
||
if Entry.BaseType:
|
||
if not isinstance(Entry.BaseType, (_t._CTypedef,)) and Entry.PtrCount == 0:
|
||
llvm_str: str = CTypeRegistry.CTypeToLLVM(type(Entry.BaseType) if isinstance(Entry.BaseType, _t.CType) else Entry.BaseType)
|
||
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
|
||
return int(llvm_str[1:])
|
||
if Entry.OriginalType:
|
||
if isinstance(Entry.OriginalType, _CTypeInfo) and Entry.OriginalType.BaseType:
|
||
if not isinstance(Entry.OriginalType.BaseType, (_t._CTypedef,)) and Entry.OriginalType.PtrCount == 0:
|
||
llvm_str: str = CTypeRegistry.CTypeToLLVM(type(Entry.OriginalType.BaseType) if isinstance(Entry.OriginalType.BaseType, _t.CType) else Entry.OriginalType.BaseType)
|
||
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
|
||
return int(llvm_str[1:])
|
||
elif isinstance(Entry.OriginalType, str):
|
||
# OriginalType 是类型名字符串(如 'CInt', 'CUnsignedInt'),
|
||
# 通过 CTypeRegistry 解析为整数位宽
|
||
cls: Any = CTypeRegistry.GetClassByName(Entry.OriginalType)
|
||
if cls:
|
||
llvm_str: str = CTypeRegistry.CTypeToLLVM(cls)
|
||
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
|
||
return int(llvm_str[1:])
|
||
|
||
# 3. 尝试 CTypeRegistry 直接按名称查找
|
||
ctype_cls: Any = CTypeRegistry.GetClassByName(name)
|
||
if ctype_cls:
|
||
llvm_str: str = CTypeRegistry.CTypeToLLVM(ctype_cls)
|
||
if llvm_str and llvm_str.startswith('i') and llvm_str[1:].isdigit():
|
||
return int(llvm_str[1:])
|
||
|
||
# 4. 特殊名称(非整数类型,但需要标记为 typedef 以跳过 opaque 定义)
|
||
_SPECIAL_TYPEDEFS: set[str] = {
|
||
'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion',
|
||
'CStruct', 'enum', 'REnum', 'renum',
|
||
'list', 'dict', 'tuple', 'set', 'str', 'bytes', 'array', 'type', 'CArray',
|
||
}
|
||
if name in _SPECIAL_TYPEDEFS:
|
||
return 0 # 标记为 typedef,但位宽为 0(非整数)
|
||
|
||
return None
|
||
|
||
def _set_node_info(self, node: ast.AST, extra_info: str = "") -> None:
|
||
if hasattr(node, 'lineno'):
|
||
self._current_lineno = node.lineno
|
||
else:
|
||
self._current_lineno = 0
|
||
if hasattr(node, 'col_offset'):
|
||
self._current_node_info = f"line {self._current_lineno}, col {node.col_offset}"
|
||
else:
|
||
self._current_node_info = f"line {self._current_lineno}"
|
||
if extra_info:
|
||
self._current_node_info += f" ({extra_info})"
|
||
|
||
def _set_source_info(self, filepath: str) -> None:
|
||
self._current_source_file = filepath
|
||
try:
|
||
with open(filepath, 'r', encoding='utf-8') as f:
|
||
self._current_source_lines = f.readlines()
|
||
except Exception: # 文件读取失败时回退为空行列表
|
||
self._current_source_lines = []
|
||
|
||
def _skip_mangle(self, name: str) -> bool:
|
||
skip_prefixes: tuple[str, ...] = ('llvm.', 'str_const_', 'printf', 'memset_pattern')
|
||
if any(name.startswith(p) for p in skip_prefixes):
|
||
return True
|
||
if '.' in name:
|
||
parts: list[str] = name.split('.', 1)
|
||
if len(parts[0]) >= 8 and all(c in '0123456789abcdef' for c in parts[0]):
|
||
return True
|
||
return False
|
||
|
||
def _mangle_name(self, name: str) -> str:
|
||
if self._skip_mangle(name):
|
||
return name
|
||
if name in self._export_funcs:
|
||
return name
|
||
if self.module_sha1:
|
||
return f"{self.module_sha1}.{name}"
|
||
return name
|
||
|
||
def _find_function(self, name: str) -> ir.Function | None:
|
||
if name in self.functions:
|
||
return self.functions[name]
|
||
g: Any = self.module.globals.get(name)
|
||
if g and isinstance(g, ir.Function):
|
||
self.functions[name] = g
|
||
return g
|
||
mangled: str = self._mangle_func_name(name)
|
||
if mangled != name:
|
||
if mangled in self.functions:
|
||
self.functions[name] = self.functions[mangled]
|
||
return self.functions[mangled]
|
||
g = self.module.globals.get(mangled)
|
||
if g and isinstance(g, ir.Function):
|
||
self.functions[mangled] = g
|
||
self.functions[name] = g
|
||
return g
|
||
for sha1 in self.ModuleSha1Map.values():
|
||
prefixed: str = f"{sha1}.{name}"
|
||
if prefixed in self.functions:
|
||
self.functions[name] = self.functions[prefixed]
|
||
return self.functions[prefixed]
|
||
g = self.module.globals.get(prefixed)
|
||
if g and isinstance(g, ir.Function):
|
||
self.functions[prefixed] = g
|
||
self.functions[name] = g
|
||
return g
|
||
return None
|
||
|
||
def _has_function(self, name: str) -> bool:
|
||
return self._find_function(name) is not None
|
||
|
||
def _get_or_declare_function(self, mangled_name: str, func_type: ir.FunctionType) -> ir.Function:
|
||
g = self.module.globals.get(mangled_name)
|
||
if g and isinstance(g, ir.Function):
|
||
return g
|
||
return ir.Function(self.module, func_type, name=mangled_name)
|
||
|
||
def _get_function(self, name: str) -> ir.Function | None:
|
||
func: ir.Function | None = self._find_function(name)
|
||
return func
|
||
|
||
def _mangle_func_name(self, name: str, module_name: str | None = None) -> str:
|
||
if name in self._export_funcs and not module_name:
|
||
return name
|
||
if name in self._export_extern_funcs:
|
||
target_sha1: str = self._export_extern_funcs[name]
|
||
if module_name:
|
||
# 显式带 module_name 调用(如 stdlib.system):即使当前模块定义了同名函数,
|
||
# 也应按模块匹配 extern,返回裸名。snprintf 之所以工作而 system 不工作,
|
||
# 就是因为 os._win32 定义了自己的 system 包装,导致旧逻辑跳过了 extern 匹配。
|
||
if module_name == target_sha1:
|
||
return name
|
||
if module_name in self.ModuleSha1Map and self.ModuleSha1Map[module_name] == target_sha1:
|
||
return name
|
||
init_name: str = f"{module_name}.__init__"
|
||
if init_name in self.ModuleSha1Map and self.ModuleSha1Map[init_name] == target_sha1:
|
||
return name
|
||
# 兜底:module_name 不在 ModuleSha1Map 中或 sha1 不匹配,
|
||
# 但函数在 _export_extern_funcs 中(C extern 不应混淆),
|
||
# 仅当当前模块未定义同名函数时才返回裸名。
|
||
if name not in self._current_module_func_names:
|
||
return name
|
||
elif name not in self._current_module_func_names:
|
||
# 无 module_name 调用(如 from stdlib import system; system()):
|
||
# 仅当当前模块未定义同名函数时才返回 extern 裸名,
|
||
# 否则让本地定义走正常 mangle 路径(本地 def 遮蔽 import 语义)。
|
||
return name
|
||
# main 函数作为程序入口点,永远不混淆
|
||
if name == 'main':
|
||
return name
|
||
# Try class_sha1_map first for class methods (e.g., 'md5.__init__' -> class 'md5')
|
||
class_sha1_map: dict[str, str] = self.class_sha1_map
|
||
if class_sha1_map:
|
||
if '.' in name:
|
||
base_class: str = name.split('.')[0]
|
||
if base_class in class_sha1_map:
|
||
sha1: str = class_sha1_map[base_class]
|
||
return f"{sha1}.{name}"
|
||
elif name in class_sha1_map:
|
||
sha1: str = class_sha1_map[name]
|
||
return f"{sha1}.{name}"
|
||
# If module_name is already a SHA1 hash (16 hex chars), use it directly
|
||
if module_name and len(module_name) == 16 and all(c in '0123456789abcdef' for c in module_name):
|
||
return f"{module_name}.{name}"
|
||
if module_name and module_name in self.ModuleSha1Map:
|
||
sha1: str = self.ModuleSha1Map[module_name]
|
||
return f"{sha1}.{name}"
|
||
# Try parent package name (e.g., 'hashlib' -> 'hashlib.__init__')
|
||
if module_name:
|
||
init_name: str = f"{module_name}.__init__"
|
||
if init_name in self.ModuleSha1Map:
|
||
sha1: str = self.ModuleSha1Map[init_name]
|
||
return f"{sha1}.{name}"
|
||
if self._skip_mangle(name):
|
||
return name
|
||
if self.module_sha1:
|
||
return f"{self.module_sha1}.{name}"
|
||
return name
|
||
|
||
def _get_source_line(self, lineno: int) -> str | None:
|
||
if 0 < lineno <= len(self._current_source_lines):
|
||
return self._current_source_lines[lineno - 1].rstrip('\r\n')
|
||
return None
|
||
|
||
def _get_node_info(self) -> str:
|
||
info: str = ""
|
||
if self._current_node_info:
|
||
info = f" [{self._current_node_info}]"
|
||
if self._current_source_file:
|
||
info += f" in {self._current_source_file}"
|
||
lineno: int = self._current_lineno
|
||
if lineno > 0:
|
||
info += f", line {lineno}:"
|
||
source_line: str | None = self._get_source_line(lineno)
|
||
if source_line:
|
||
info += f"\n → {source_line}"
|
||
return info
|
||
|
||
# ========== 统一工具方法 ==========
|
||
|
||
def _create_string_global(self, s: str, name: str | None = None) -> ir.Constant:
|
||
"""创建字符串全局变量并返回 i8* 指针。
|
||
|
||
统一字符串全局变量创建模式:编码为 utf-8 + '\\x00' 终止符,
|
||
创建 internal linkage 的 GlobalVariable,返回 i8* 指针常量。
|
||
"""
|
||
str_val: str = s + '\x00'
|
||
str_bytes: bytes = str_val.encode('utf-8')
|
||
arr_type: ir.ArrayType = ir.ArrayType(ir.IntType(8), len(str_bytes))
|
||
gv_name: str = name or f"str_const_{self.string_const_counter}"
|
||
self.string_const_counter += 1
|
||
gv: ir.GlobalVariable = ir.GlobalVariable(self.module, arr_type, name=gv_name)
|
||
gv.initializer = ir.Constant(arr_type, bytearray(str_bytes))
|
||
gv.linkage = 'internal'
|
||
return ir.Constant(ir.PointerType(ir.IntType(8)), gv.get_reference())
|
||
|
||
def _create_doc_global(self, symbol_name: str, docstring: str | None) -> None:
|
||
"""为符号创建 __doc__ 全局常量。
|
||
|
||
- docstring 为 None 或空字符串时,不创建常量(访问时内联空指针)
|
||
- slice_level != 0(优化开启)时,内容视为空
|
||
- 非空时创建 internal linkage、global_constant=True 的只读字符串常量
|
||
- 常量名格式:{module_sha1}.{symbol_name}.__doc__
|
||
"""
|
||
slice_level: int = getattr(self._Trans, 'SliceLevel', 3)
|
||
if slice_level != 0:
|
||
docstring = None
|
||
if docstring is None or docstring == '':
|
||
self._doc_strings[symbol_name] = None
|
||
return
|
||
self._doc_strings[symbol_name] = docstring
|
||
mangled: str = self._mangle_name(f"{symbol_name}.__doc__")
|
||
self._create_string_global(docstring, name=mangled)
|
||
gv: ir.GlobalVariable | None = self.module.globals.get(mangled)
|
||
if gv is not None:
|
||
gv.global_constant = True
|
||
|
||
def _get_doc_ptr(self, symbol_name: str) -> ir.Value | None:
|
||
"""获取符号 __doc__ 的 i8* 指针。
|
||
|
||
- 若符号未注册 __doc__,返回 None(调用方回退到其他解析)
|
||
- 若 __doc__ 为空(无 docstring 或优化剥离),返回 i8* null 内联空指针
|
||
- 若 __doc__ 非空,返回指向字符串全局常量的 i8* 指针
|
||
- 跨模块 docstring(在 _doc_strings 中有文本但 module.globals 无对应常量)首次访问时创建本地 internal linkage 只读副本
|
||
"""
|
||
if symbol_name not in self._doc_strings:
|
||
return None
|
||
docstring: str | None = self._doc_strings[symbol_name]
|
||
if docstring is None or docstring == '':
|
||
return ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||
mangled: str = self._mangle_name(f"{symbol_name}.__doc__")
|
||
gv: ir.GlobalVariable | None = self.module.globals.get(mangled)
|
||
if gv is None:
|
||
# 跨模块 docstring:创建本地 internal linkage 只读字符串常量副本
|
||
self._create_string_global(docstring, name=mangled)
|
||
gv = self.module.globals.get(mangled)
|
||
if gv is None:
|
||
return ir.Constant(ir.PointerType(ir.IntType(8)), None)
|
||
gv.global_constant = True
|
||
zero: ir.Constant = ir.Constant(ir.IntType(32), 0)
|
||
return self.builder.gep(gv, [zero, zero], name=f"{symbol_name}_doc_ptr")
|
||
|
||
def _apply_bswap_if_big(self, val: ir.Value, byte_order: str, name: str) -> ir.Value:
|
||
"""大端字节序时对整数应用 bswap,否则原值返回。
|
||
|
||
仅对 16/32/64 位整数生效,统一 bswap 逻辑。
|
||
"""
|
||
if byte_order == 'big' and isinstance(val.type, ir.IntType) and val.type.width in (16, 32, 64):
|
||
return self.builder.bswap(val, name=name)
|
||
return val
|
||
|
||
def _zero_value_for_type(self, llvm_type: ir.Type) -> ir.Constant | None:
|
||
"""为指定 LLVM 类型生成零值常量。
|
||
|
||
合并原 HandlesAssign._zero_value 与 StructGen._zero_value_for_type 的逻辑。
|
||
返回 ir.Constant 或 None(无法生成零值的类型,如 opaque struct)。
|
||
"""
|
||
if isinstance(llvm_type, ir.IntType):
|
||
return ir.Constant(llvm_type, 0)
|
||
elif isinstance(llvm_type, (ir.FloatType, ir.DoubleType)):
|
||
return ir.Constant(llvm_type, 0.0)
|
||
elif isinstance(llvm_type, ir.PointerType):
|
||
return ir.Constant(llvm_type, None)
|
||
elif isinstance(llvm_type, ir.ArrayType):
|
||
elem_zv: ir.Constant | None = self._zero_value_for_type(llvm_type.element)
|
||
if elem_zv is None:
|
||
return None
|
||
return ir.Constant(llvm_type, [elem_zv] * llvm_type.count)
|
||
elif isinstance(llvm_type, ir.BaseStructType):
|
||
if llvm_type.elements is not None and len(llvm_type.elements) > 0:
|
||
elem_zvs: list[ir.Constant | None] = [self._zero_value_for_type(m) for m in llvm_type.elements]
|
||
if any(zv is None for zv in elem_zvs):
|
||
return None
|
||
return ir.Constant(llvm_type, elem_zvs)
|
||
return None
|
||
return None |