修复了大量存在的问题,增加了假鸭子类型等等机制

This commit is contained in:
2026-06-25 14:49:46 +08:00
parent 19f2787db0
commit d88d11b646
827 changed files with 32617 additions and 18316 deletions

View File

@@ -1,13 +1,15 @@
from __future__ import annotations
from typing import Any, Callable
import re
import ast
import llvmlite.ir as ir
from llvmlite.ir.values import _Undefined
from lib.includes import t as _t
class StructGenMixin:
def _get_align(self, llvm_type):
def _get_align(self, llvm_type: ir.Type) -> int:
if isinstance(llvm_type, ir.IntType):
return max(1, llvm_type.width // 8)
if isinstance(llvm_type, ir.FloatType):
@@ -28,7 +30,53 @@ class StructGenMixin:
return 0
return 4
def _get_struct_size(self, llvm_type):
def _resolve_opaque_struct(self, llvm_type: ir.Type) -> ir.Type:
"""尝试从 Gen.structs 中查找已解析的同名 struct解决跨模块 struct 类型对象不一致的问题"""
if not isinstance(llvm_type, ir.IdentifiedStructType):
return llvm_type
if llvm_type.elements is not None and len(llvm_type.elements) > 0:
return llvm_type
# opaque struct尝试通过名称在 Gen.structs 中查找已解析的版本
st_name: str
try:
st_name = llvm_type.name
except Exception:
return llvm_type
if not st_name:
return llvm_type
# 提取短名称
short_name: str = st_name
if '.' in st_name:
short_name = st_name.split('.', 1)[1]
# 尝试短名称查找
if short_name in self.structs:
resolved: ir.IdentifiedStructType = self.structs[short_name]
if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0:
return resolved
# 尝试全名查找
if st_name in self.structs:
resolved: ir.IdentifiedStructType = self.structs[st_name]
if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0:
return resolved
# 尝试通过导入处理器从 stub 文件加载 struct 定义
import_handler: Any = getattr(self, '_import_handler_ref', None)
if import_handler is not None:
try:
import_handler._TryLoadStructFromStub(short_name, self)
except Exception:
pass
# 加载后再次查找
if short_name in self.structs:
resolved = self.structs[short_name]
if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0:
return resolved
if st_name in self.structs:
resolved = self.structs[st_name]
if isinstance(resolved, ir.IdentifiedStructType) and resolved.elements is not None and len(resolved.elements) > 0:
return resolved
return llvm_type
def _get_struct_size(self, llvm_type: ir.Type) -> int:
if isinstance(llvm_type, ir.IntType):
return max(1, llvm_type.width // 8)
if isinstance(llvm_type, ir.FloatType):
@@ -40,11 +88,11 @@ class StructGenMixin:
if isinstance(llvm_type, ir.ArrayType):
return self._get_struct_size(llvm_type.element) * llvm_type.count
if isinstance(llvm_type, ir.LiteralStructType):
total = 0
max_align = 1
total: int = 0
max_align: int = 1
for f in llvm_type.fields:
fa = self._get_align(f)
fs = self._get_struct_size(f)
fa: int = self._get_align(f)
fs: int = self._get_struct_size(f)
max_align = max(max_align, fa)
if fa > 1:
total = (total + fa - 1) // fa * fa
@@ -53,13 +101,15 @@ class StructGenMixin:
total = (total + max_align - 1) // max_align * max_align
return total
if isinstance(llvm_type, ir.IdentifiedStructType):
# 尝试解析 opaque struct 为已注册的版本
llvm_type = self._resolve_opaque_struct(llvm_type)
if llvm_type.elements is None or len(llvm_type.elements) == 0:
return self.ptr_size # opaque struct, assume pointer size
total = 0
max_align = 1
total: int = 0
max_align: int = 1
for f in llvm_type.elements:
fa = self._get_align(f)
fs = self._get_struct_size(f)
fa: int = self._get_align(f)
fs: int = self._get_struct_size(f)
max_align = max(max_align, fa)
if fa > 1:
total = (total + fa - 1) // fa * fa
@@ -70,10 +120,10 @@ class StructGenMixin:
return 4
@staticmethod
def _strip_unnecessary_quotes(ir_str):
def _unquote(m):
prefix = m.group(1)
name = m.group(2)
def _strip_unnecessary_quotes(ir_str: str) -> str:
def _unquote(m: re.Match) -> str:
prefix: str = m.group(1)
name: str = m.group(2)
if '.' in name:
return m.group(0)
if re.match(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$', name):
@@ -81,9 +131,10 @@ class StructGenMixin:
return m.group(0)
return re.sub(r'([@%])"([^"]+)"', _unquote, ir_str)
def finalize(self):
def finalize(self) -> str:
self._set_Vtable_initializers()
self._fix_global_var_init()
ir_text: str
try:
ir_text = str(self.module)
except TypeError as e:
@@ -96,11 +147,12 @@ class StructGenMixin:
pass
raise
ir_text = self._strip_unnecessary_quotes(ir_text)
struct_defs = []
struct_names = set()
struct_defs: list[str] = []
struct_names: set[str] = set()
for ClassName, struct_type in self.structs.items():
if isinstance(struct_type, ir.IdentifiedStructType):
sname = struct_type.name
sname: str = struct_type.name
sname_ir: str
if sname[0].isdigit() or '.' in sname or not sname.replace('_', '').replace('.', '').isalnum():
sname_ir = f'%"{sname}"'
else:
@@ -110,19 +162,20 @@ class StructGenMixin:
struct_names.add(sname)
struct_defs.append(f'{sname_ir} = type opaque')
continue
elems = ', '.join(str(e) for e in struct_type.elements)
elems: str = ', '.join(str(e) for e in struct_type.elements)
if struct_type.packed:
struct_defs.append(f'{sname_ir} = type <{{ {elems} }}>')
else:
struct_defs.append(f'{sname_ir} = type {{ {elems} }}')
struct_names.add(sname)
if struct_defs:
lines = ir_text.split('\n')
filtered = []
lines: list[str] = ir_text.split('\n')
filtered: list[str] = []
for line in lines:
stripped = line.strip()
skip = False
stripped: str = line.strip()
skip: bool = False
for name in struct_names:
patterns: list[str]
if name[0].isdigit() or '.' in name or not name.replace('_', '').replace('.', '').isalnum():
patterns = [f'%"{name}" = type', f'%"{name}"=type', f'%{name} = type', f'%{name}=type']
else:
@@ -136,17 +189,17 @@ class StructGenMixin:
if not skip:
filtered.append(line)
ir_text = '\n'.join(filtered)
header_end = ir_text.find('\ndefine')
header_end: int = ir_text.find('\ndefine')
if header_end == -1:
header_end = ir_text.find('\ndeclare')
if header_end == -1:
header_end = ir_text.find('\n@')
if header_end == -1:
header_end = len(ir_text)
insert_pos = ir_text.rfind('\n', 0, header_end)
insert_pos: int = ir_text.rfind('\n', 0, header_end)
if insert_pos == -1:
insert_pos = header_end
struct_block = '\n'.join(struct_defs) + '\n'
struct_block: str = '\n'.join(struct_defs) + '\n'
ir_text = ir_text[:insert_pos + 1] + struct_block + ir_text[insert_pos + 1:]
for name in struct_names:
if name[0].isdigit() or '.' in name:
@@ -158,13 +211,13 @@ class StructGenMixin:
return ir_text
def _collect_classes_and_methods(self, ast_nodes, parent=None):
current_class = None
def _collect_classes_and_methods(self, ast_nodes: list[ast.AST], parent: ast.AST | None = None) -> None:
current_class: str | None = None
for node in ast_nodes:
if isinstance(node, str):
continue
node.parent = parent
node_type = type(node).__name__
node_type: str = type(node).__name__
if node_type == 'Struct':
if hasattr(node, 'name'):
current_class = node.name
@@ -173,11 +226,11 @@ class StructGenMixin:
if hasattr(node, 'decls') and node.decls:
for decl in node.decls:
if type(decl).__name__ == 'Decl' and hasattr(decl, 'name'):
member_type = self._get_type(decl.type) if hasattr(decl, 'type') else ir.IntType(32)
member_type: ir.Type = self._get_type(decl.type) if hasattr(decl, 'type') else ir.IntType(32)
self.class_members[current_class].append((decl.name, member_type))
elif node_type == 'FuncDef':
if current_class and current_class in self.class_methods:
MethodName = node.decl.name if hasattr(node.decl, 'name') else 'unknown_method'
MethodName: str = node.decl.name if hasattr(node.decl, 'name') else 'unknown_method'
if not MethodName.startswith(f"{current_class}."):
MethodName = f"{current_class}.{MethodName}"
self.class_methods[current_class].append(MethodName)
@@ -186,10 +239,10 @@ class StructGenMixin:
elif hasattr(node, 'BlockItems') and node.BlockItems:
self._collect_classes_and_methods(node.BlockItems, parent=node)
def _generate_structs(self):
all_classes = set(self.class_methods.keys()) | set(self.class_members.keys())
def _generate_structs(self) -> None:
all_classes: set[str] = set(self.class_methods.keys()) | set(self.class_members.keys())
preserved_structs = {}
preserved_structs: dict[str, ir.IdentifiedStructType] = {}
for name, st in self.structs.items():
if name not in all_classes:
preserved_structs[name] = st
@@ -204,25 +257,24 @@ class StructGenMixin:
# Step 1: 先为所有类创建空的 struct确保后面可以正确引用
all_classes = set(self.class_methods.keys()) | set(self.class_members.keys())
for ClassName in all_classes:
is_packed = ClassName in self.class_packed
if hasattr(self, 'SymbolTable') and self.SymbolTable and self.SymbolTable.has(ClassName):
Entry = self.SymbolTable[ClassName]
if Entry.IsExceptionClass:
is_packed: bool = ClassName in self.class_packed
if hasattr(self, 'SymbolTable') and self.SymbolTable:
Entry = self.SymbolTable.lookup(ClassName)
if Entry and Entry.IsExceptionClass:
continue
if Entry.IsEnum:
if Entry and Entry.IsEnum:
if not Entry.IsRenum:
continue
if Entry.IsTypedef:
if Entry and Entry.IsTypedef:
if Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)):
import lib.includes.t as _t
if not isinstance(Entry.BaseType, (_t._CTypedef,)):
continue
if ClassName in self.structs:
if is_packed:
self.structs[ClassName].packed = True
continue
mangled_name = self._mangle_name(ClassName)
struct_type = ir.IdentifiedStructType(self.module, mangled_name, packed=is_packed)
mangled_name: str = self._mangle_name(ClassName)
struct_type: ir.IdentifiedStructType = ir.IdentifiedStructType(self.module, mangled_name, packed=is_packed)
self.structs[ClassName] = struct_type
# Step 2: 解析跨模块的成员类型
@@ -231,30 +283,30 @@ class StructGenMixin:
continue
for i, (member_name, member_type) in enumerate(self.class_members[ClassName]):
if member_name in annotations:
annotation = annotations[member_name]
ResolvedType = None
annotation: Any = annotations[member_name]
ResolvedType: ir.Type | None = None
if isinstance(annotation, ast.Attribute):
ClassTypeName = annotation.attr
ClassTypeName: str = annotation.attr
if ClassTypeName in self.structs:
ResolvedType = self.structs[ClassTypeName]
elif isinstance(annotation, ast.BinOp) and isinstance(annotation.op, ast.BitOr):
left = annotation.left
left: Any = annotation.left
if isinstance(left, ast.Attribute):
ClassTypeName = left.attr
ClassTypeName: str = left.attr
if ClassTypeName in self.structs:
ResolvedType = self.structs[ClassTypeName]
if ResolvedType:
self.class_members[ClassName][i] = (member_name, ResolvedType)
struct_name_map = {}
struct_name_map: dict[str, ir.IdentifiedStructType] = {}
for struct_name, struct in self.structs.items():
try:
struct_name_map[struct.name] = struct
except AssertionError:
struct_name_map[struct_name] = struct
orig = getattr(struct, '_original_name', None)
orig: Any = getattr(struct, '_original_name', None)
if orig:
struct_name_map[orig] = struct
@@ -264,81 +316,85 @@ class StructGenMixin:
continue
for i, (member_name, member_type) in enumerate(self.class_members[ClassName]):
if isinstance(member_type, ir.PointerType):
pointee = member_type.pointee
pointee: ir.Type = member_type.pointee
if isinstance(pointee, ir.IdentifiedStructType):
pname: str | None
try:
pname = pointee.name
except AssertionError:
pname = None
struct = struct_name_map.get(pname) if pname else None
struct: ir.IdentifiedStructType | None = struct_name_map.get(pname) if pname else None
if struct is None:
orig = getattr(pointee, '_original_name', None)
orig: Any = getattr(pointee, '_original_name', None)
struct = struct_name_map.get(orig) if orig else None
if struct is not None:
self.class_members[ClassName][i] = (member_name, ir.PointerType(struct))
else:
raw_name = pname or ''
raw_name: str = pname or ''
if raw_name.startswith('struct.'):
raw_name = raw_name[7:]
new_struct = self._get_or_create_struct(raw_name)
new_struct: ir.IdentifiedStructType = self._get_or_create_struct(raw_name)
self.class_members[ClassName][i] = (member_name, ir.PointerType(new_struct))
elif isinstance(member_type, ir.IdentifiedStructType):
mname: str | None
try:
mname = member_type.name
except AssertionError:
mname = None
struct = struct_name_map.get(mname) if mname else None
struct: ir.IdentifiedStructType | None = struct_name_map.get(mname) if mname else None
if struct is None:
orig = getattr(member_type, '_original_name', None)
orig: Any = getattr(member_type, '_original_name', None)
struct = struct_name_map.get(orig) if orig else None
if struct is not None:
self.class_members[ClassName][i] = (member_name, struct)
else:
raw_name = mname or ''
raw_name: str = mname or ''
if raw_name.startswith('struct.'):
raw_name = raw_name[7:]
new_struct = self._get_or_create_struct(raw_name)
new_struct: ir.IdentifiedStructType = self._get_or_create_struct(raw_name)
self.class_members[ClassName][i] = (member_name, new_struct)
# Step 4: 创建最终的 structs 并设置正确的成员类型
for ClassName in all_classes:
if hasattr(self, 'SymbolTable') and self.SymbolTable and self.SymbolTable.has(ClassName):
Entry = self.SymbolTable[ClassName]
if Entry.IsExceptionClass:
if hasattr(self, 'SymbolTable') and self.SymbolTable:
Entry = self.SymbolTable.lookup(ClassName)
if Entry and Entry.IsExceptionClass:
continue
if Entry.IsEnum:
if Entry and Entry.IsEnum:
if not Entry.IsRenum:
continue
existing_st = self.structs.get(ClassName)
existing_st: ir.IdentifiedStructType | None = self.structs.get(ClassName)
if isinstance(existing_st, ir.IdentifiedStructType) and existing_st.elements is not None and len(existing_st.elements) > 0:
# 即使 struct 已有元素,也需要修正 packed 属性
if ClassName in self.class_packed and not existing_st.packed:
existing_st.packed = True
continue
has_vtable = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes
has_vtable: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes
if not has_vtable:
p = self.class_parent.get(ClassName)
p: str | None = self.class_parent.get(ClassName)
while p:
if p in self.class_vtable or p in self._cross_module_vtable_classes:
has_vtable = True
self.class_vtable.add(ClassName)
break
p = self.class_parent.get(p)
has_bitfield = ClassName in self.class_member_bitfields and any(
has_bitfield: bool = ClassName in self.class_member_bitfields and any(
self.class_member_bitfields[ClassName].get(name, 0) > 0
for name, _ in self.class_members.get(ClassName, [])
)
all_members = self.class_members.get(ClassName, [])
all_bitfield = all(
all_members: list[tuple[str, ir.Type]] = self.class_members.get(ClassName, [])
all_bitfield: bool = all(
self.class_member_bitfields.get(ClassName, {}).get(name, 0) > 0
for name, _ in all_members
) if all_members else False
mangled_name = self._mangle_name(ClassName)
mangled_name: str = self._mangle_name(ClassName)
member_types: list[ir.Type]
if has_bitfield and all_bitfield:
total_bits = sum(self.class_member_bitfields.get(ClassName, {}).get(name, 0)
total_bits: int = sum(self.class_member_bitfields.get(ClassName, {}).get(name, 0)
for name, _ in all_members)
storage_type: ir.IntType
if total_bits <= 8:
storage_type = ir.IntType(8)
elif total_bits <= 16:
@@ -348,10 +404,10 @@ class StructGenMixin:
else:
storage_type = ir.IntType(64)
member_types = [storage_type]
bitfield_offsets = {}
current_bit_offset = 0
bitfield_offsets: dict[str, int] = {}
current_bit_offset: int = 0
for name, _ in all_members:
bit_width = self.class_member_bitfields.get(ClassName, {}).get(name, 0)
bit_width: int = self.class_member_bitfields.get(ClassName, {}).get(name, 0)
bitfield_offsets[name] = current_bit_offset
current_bit_offset += bit_width
self.class_member_bitoffsets[ClassName] = bitfield_offsets
@@ -368,14 +424,14 @@ class StructGenMixin:
member_types = [ir.IntType(8)]
# 获取之前创建的 struct 并设置成员
struct_type = self.structs[ClassName]
struct_type: ir.IdentifiedStructType = self.structs[ClassName]
if ClassName in self.class_packed:
struct_type.packed = True
# 只在未设置 body 时设置,避免重复定义错误
if struct_type.elements is None:
struct_type.set_body(*member_types)
def _create_Vtable_globals(self):
def _create_Vtable_globals(self) -> None:
for ClassName, methods in self.class_methods.items():
if ClassName in self.Vtables:
continue
@@ -383,19 +439,19 @@ class StructGenMixin:
continue
if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes:
continue
VtableType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
Vtable = ir.GlobalVariable(self.module, VtableType, name=self._mangle_name(f"{ClassName}_Vtable"))
VtableType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
Vtable: ir.GlobalVariable = ir.GlobalVariable(self.module, VtableType, name=self._mangle_name(f"{ClassName}_Vtable"))
Vtable.initializer = ir.Constant(VtableType, [ir.Constant(ir.PointerType(ir.IntType(8)), None)] * len(methods))
Vtable.linkage = 'internal'
self.Vtables[ClassName] = Vtable
def _fix_global_var_init(self):
def _fix_global_var_init(self) -> None:
for gv_name, gv in list(self.module.globals.items()):
if not isinstance(gv, ir.GlobalVariable):
continue
if gv.linkage in ('external', 'extern_weak'):
continue
needs_fix = False
needs_fix: bool = False
if gv.initializer is None:
needs_fix = True
elif hasattr(gv.initializer, 'constant') and isinstance(gv.initializer.constant, _Undefined):
@@ -410,48 +466,27 @@ class StructGenMixin:
if gv_name.startswith('str_const_') or gv_name.endswith('_Vtable') or gv_name.endswith('_str'):
gv.linkage = 'internal'
def _zero_value_for_type(self, var_type):
if isinstance(var_type, ir.IntType):
return ir.Constant(var_type, 0)
elif isinstance(var_type, (ir.FloatType, ir.DoubleType)):
return ir.Constant(var_type, 0.0)
elif isinstance(var_type, ir.PointerType):
return ir.Constant(var_type, None)
elif isinstance(var_type, ir.ArrayType):
elem_zv = self._zero_value_for_type(var_type.element)
if elem_zv is None:
return None
return ir.Constant(var_type, [elem_zv] * var_type.count)
elif isinstance(var_type, ir.BaseStructType):
if var_type.elements is not None and len(var_type.elements) > 0:
elem_zvs = [self._zero_value_for_type(m) for m in var_type.elements]
if any(zv is None for zv in elem_zvs):
return None
return ir.Constant(var_type, elem_zvs)
return None
return None
def _set_Vtable_initializers(self):
def _set_Vtable_initializers(self) -> None:
for ClassName, methods in self.class_methods.items():
if ClassName not in self.Vtables:
continue
if not methods:
continue
struct_type = self.structs.get(ClassName)
struct_type: ir.IdentifiedStructType | None = self.structs.get(ClassName)
if not struct_type:
continue
Vtable = self.Vtables[ClassName]
Vtable_entries = []
Vtable: ir.GlobalVariable = self.Vtables[ClassName]
Vtable_entries: list[ir.Constant] = []
for MethodName in methods:
short_name = MethodName.split('.')[-1] if '.' in MethodName else MethodName
full_MethodName = f"{ClassName}.{short_name}"
func = None
short_name: str = MethodName.split('.')[-1] if '.' in MethodName else MethodName
full_MethodName: str = f"{ClassName}.{short_name}"
func: ir.Function | None = None
if full_MethodName in self.functions:
func = self.functions[full_MethodName]
if func is None:
parent_cls = self.class_parent.get(ClassName)
parent_cls: str | None = self.class_parent.get(ClassName)
while parent_cls:
parent_full = f"{parent_cls}.{short_name}"
parent_full: str = f"{parent_cls}.{short_name}"
if parent_full in self.functions:
func = self.functions[parent_full]
break
@@ -460,4 +495,4 @@ class StructGenMixin:
Vtable_entries.append(ir.Constant(ir.PointerType(ir.IntType(8)), None))
continue
Vtable_entries.append(func.bitcast(ir.PointerType(ir.IntType(8))))
Vtable.initializer = ir.Constant(Vtable.type.pointee, Vtable_entries)
Vtable.initializer = ir.Constant(Vtable.type.pointee, Vtable_entries)