Files
TransPyC/lib/core/LLVMCG/StructGen.py

629 lines
34 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 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: ir.Type) -> int:
if isinstance(llvm_type, ir.IntType):
return max(1, llvm_type.width // 8)
if isinstance(llvm_type, ir.FloatType):
return 4
if isinstance(llvm_type, ir.DoubleType):
return 8
if isinstance(llvm_type, ir.PointerType):
return self.ptr_size
if isinstance(llvm_type, ir.ArrayType):
return self._get_align(llvm_type.element)
if isinstance(llvm_type, ir.LiteralStructType):
return max((self._get_align(f) for f in llvm_type.elements), default=1)
if isinstance(llvm_type, ir.IdentifiedStructType):
if llvm_type.elements is None or len(llvm_type.elements) == 0:
return self.ptr_size # opaque struct, assume pointer alignment
return max((self._get_align(f) for f in llvm_type.elements), default=1)
if isinstance(llvm_type, ir.VoidType):
return 0
return 4
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 = self._import_handler_ref
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):
return 4
if isinstance(llvm_type, ir.DoubleType):
return 8
if isinstance(llvm_type, ir.PointerType):
return self.ptr_size
if isinstance(llvm_type, ir.ArrayType):
return self._get_struct_size(llvm_type.element) * llvm_type.count
if isinstance(llvm_type, ir.LiteralStructType):
total: int = 0
max_align: int = 1
for f in llvm_type.fields:
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
total += fs
if max_align > 1:
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: int = 0
max_align: int = 1
for f in llvm_type.elements:
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
total += fs
if max_align > 1:
total = (total + max_align - 1) // max_align * max_align
return total
return 4
@staticmethod
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):
return prefix + name
return m.group(0)
return re.sub(r'([@%])"([^"]+)"', _unquote, ir_str)
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:
for func in self.module.functions:
for block in func.blocks:
for instr in block.instructions:
try:
str(instr)
except TypeError as te:
pass
raise
ir_text = self._strip_unnecessary_quotes(ir_text)
struct_defs: list[str] = []
struct_names: set[str] = set()
for ClassName, struct_type in self.structs.items():
if isinstance(struct_type, ir.IdentifiedStructType):
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:
sname_ir = f'%{sname}'
if struct_type.elements is None or len(struct_type.elements) == 0:
if ClassName not in self.typedef_int_widths:
struct_names.add(sname)
struct_defs.append(f'{sname_ir} = type opaque')
continue
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: list[str] = ir_text.split('\n')
filtered: list[str] = []
for line in lines:
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:
patterns = [f'%{name} = type', f'%{name}= type', f'%{name}=type']
for p in patterns:
if stripped.startswith(p):
skip = True
break
if skip:
break
if not skip:
filtered.append(line)
ir_text = '\n'.join(filtered)
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: int = ir_text.rfind('\n', 0, header_end)
if insert_pos == -1:
insert_pos = header_end
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:
ir_text = re.sub(
r'%' + re.escape(name) + r'(?=[^a-zA-Z0-9_$\.]|$)',
r'%"' + name + r'"',
ir_text
)
return ir_text
def _generate_structs(self) -> None:
all_classes: set[str] = set(self.class_methods.keys()) | set(self.class_members.keys())
preserved_structs: dict[str, ir.IdentifiedStructType] = {}
for name, st in self.structs.items():
if name not in all_classes:
preserved_structs[name] = st
elif isinstance(st, ir.IdentifiedStructType):
preserved_structs[name] = st
self.structs.clear()
for name, st in preserved_structs.items():
self.structs[name] = st
# Step 1: 先为所有类创建空的 struct确保后面可以正确引用
all_classes = set(self.class_methods.keys()) | set(self.class_members.keys())
for ClassName in all_classes:
is_packed: bool = ClassName in self.class_packed
if self.SymbolTable:
Entry = self.SymbolTable.lookup(ClassName)
if Entry and Entry.IsExceptionClass:
continue
# 注意:类名可能与 CEnum 成员名冲突(如 ASTKind.Module 枚举成员与 Module 类同名)
# 如果 ClassName 在 class_methods 中,表明是 _EmitClassLlvm 显式处理的常规类,
# 不应被 IsEnum/IsTypedef 检查跳过
if Entry and Entry.IsEnum and ClassName not in self.class_methods:
if not Entry.IsRenum:
continue
if Entry and Entry.IsTypedef and ClassName not in self.class_methods:
if Entry.BaseType and not isinstance(Entry.BaseType, (type(None),)):
if not isinstance(Entry.BaseType, (_t._CTypedef,)):
continue
if ClassName in self.structs:
if is_packed:
self.structs[ClassName].packed = True
continue
# 修复跨模块类型定义冲突:如果类是从其他模块导入的(已在 class_sha1_map 注册),
# 必须使用导入的 source_sha1 作为前缀,而非本地模块的 sha1。
# 否则会创建缺少基类字段(如 GSListNode.Next的本地类型定义
# 导致字段索引错位 → 访问违规崩溃。
_imported_sha1: str = self.class_sha1_map.get(ClassName, '')
if _imported_sha1:
mangled_name: str = f"{_imported_sha1}.{ClassName}"
else:
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: 解析跨模块的成员类型
for ClassName, annotations in self.class_member_annotations.items():
if ClassName not in self.class_members:
continue
for i, (member_name, member_type) in enumerate(self.class_members[ClassName]):
if member_name in annotations:
annotation: Any = annotations[member_name]
ResolvedType: ir.Type | None = None
if isinstance(annotation, ast.Attribute):
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: Any = annotation.left
if isinstance(left, ast.Attribute):
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: 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: Any = getattr(struct, '_original_name', None)
if orig:
struct_name_map[orig] = struct
# Step 3: 更新成员类型,确保使用正确的 mangled struct 引用
for ClassName in all_classes:
if ClassName not in self.class_members:
continue
for i, (member_name, member_type) in enumerate(self.class_members[ClassName]):
if isinstance(member_type, ir.PointerType):
pointee: ir.Type = member_type.pointee
if isinstance(pointee, ir.IdentifiedStructType):
pname: str | None
try:
pname = pointee.name
except AssertionError:
pname = None
struct: ir.IdentifiedStructType | None = struct_name_map.get(pname) if pname else None
if struct is 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: str = pname or ''
if raw_name.startswith('struct.'):
raw_name = raw_name[7:]
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: ir.IdentifiedStructType | None = struct_name_map.get(mname) if mname else None
if struct is 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: str = mname or ''
if raw_name.startswith('struct.'):
raw_name = raw_name[7:]
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 self.SymbolTable:
Entry = self.SymbolTable.lookup(ClassName)
if Entry and Entry.IsExceptionClass:
continue
# 注意:类名可能与 CEnum 成员名冲突(如 ASTKind.Constant 枚举成员与 Constant 类同名)
# 如果 ClassName 在 class_methods 中,表明是 _EmitClassLlvm 显式处理的常规类,
# 不应被 IsEnum 检查跳过(与 Step 1 的守卫保持一致)
if Entry and Entry.IsEnum and ClassName not in self.class_methods:
if not Entry.IsRenum:
continue
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 body 是否不完整(元素数少于 class_members + vtable 预期)。
# 常见于跨模块继承:子类 struct 在父类 class_members 加载前从 stub 生成,
# stub 中的定义可能不完整或类型不正确(如 GSList* 代替 AST*、i8* 代替 i32
# 此处检测到不完整后清除 _elements 和 stub 缓存,让后续代码重新从 stub 加载。
_has_vtable_precheck: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes
if not _has_vtable_precheck:
_p_pre: str | None = self.class_parent.get(ClassName)
while _p_pre:
if _p_pre in self.class_vtable or _p_pre in self._cross_module_vtable_classes:
_has_vtable_precheck = True
break
_p_pre = self.class_parent.get(_p_pre)
_expected_count_pre: int = len(self.class_members.get(ClassName, [])) + (1 if _has_vtable_precheck else 0)
# has_vtable 时,首字段必须是 i8*vtable 指针)。
# 若首字段非指针(如 i8 占位符struct body 不完整,需清除重新加载。
_vtable_first_ok: bool = True
if _has_vtable_precheck and len(existing_st.elements) > 0:
_vtable_first_ok = isinstance(existing_st.elements[0], ir.PointerType)
# 检测 T* 占位类型(未特化的泛型类型参数)。
# 当 struct 包含 T* 字段时(如 BasicBlock 继承 GSListNode[BasicBlock] 但 stub 未特化),
# 说明 stub 使用了未特化的基类,需清除重新生成。
_has_t_placeholder_pre: bool = False
for _elem_pre in existing_st.elements:
if isinstance(_elem_pre, ir.PointerType) and isinstance(_elem_pre.pointee, ir.IdentifiedStructType):
_pname_pre: str = _elem_pre.pointee.name
_short_pre: str = _pname_pre.rsplit('.', 1)[-1] if '.' in _pname_pre else _pname_pre
if _short_pre == 'T':
_has_t_placeholder_pre = True
break
if len(existing_st.elements) >= _expected_count_pre and _vtable_first_ok and not _has_t_placeholder_pre:
if ClassName in self.class_packed and not existing_st.packed:
existing_st.packed = True
continue
# struct body 不完整,清除 _elements 和 stub 缓存以便重新加载
existing_st._elements = None
_import_handler_pre: Any = self._import_handler_ref
if _import_handler_pre is not None:
_cache_key_pre: tuple = (id(self), ClassName)
if _cache_key_pre in _import_handler_pre._struct_Load_cache:
del _import_handler_pre._struct_Load_cache[_cache_key_pre]
has_vtable: bool = ClassName in self.class_vtable or ClassName in self._cross_module_vtable_classes
if not has_vtable:
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: 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: list[tuple[str, ir.Type]] = self.class_members.get(ClassName, [])
# 跳过正在发射中且成员尚未填充的类(递归特化时避免过早设置空 body
if not all_members and not has_vtable and ClassName in self._classes_in_progress:
continue
# 字段收集期间触发的嵌套 _generate_structsclass_members 可能不完整,
# set_body 只能调用一次,跳过等字段收集完成后再设置 body
if ClassName in self._collecting_members_set:
continue
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: str = self._mangle_name(ClassName)
member_types: list[ir.Type]
if has_bitfield and all_bitfield:
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:
storage_type = ir.IntType(16)
elif total_bits <= 32:
storage_type = ir.IntType(32)
else:
storage_type = ir.IntType(64)
member_types = [storage_type]
bitfield_offsets: dict[str, int] = {}
current_bit_offset: int = 0
for name, _ in all_members:
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
else:
member_types = []
if has_vtable:
member_types.append(ir.PointerType(ir.IntType(8)))
if ClassName in self.class_members:
for _, member_type in self.class_members[ClassName]:
if member_type is None:
member_type = ir.IntType(32)
member_types.append(member_type)
else:
if has_vtable:
# has_vtable 但 class_members 为空(跨模块导入类):
# 保持 member_types 为空([i8*] 占位会导致 stub 加载跳过,
# 因为 set_body 后 is_opaque=False。让 struct 保持 opaque
# 由 _TryLoadStructFromStub 设置完整 body。
member_types = []
else:
# 无 vtable 且 class_members 为空:常见于 register_method 早期
# 调用 _generate_structs此时 class_members[ClassName]=[] 但尚未
# 填充实际字段)。保持 opaque避免 set_body(*[i8]) 永久损坏 struct
# llvmlite 的 set_body 只能调用一次)。后续 _generate_structs 调用
# 会从 class_members 或 stub 设置正确 body。
member_types = []
# 获取之前创建的 struct 并设置成员
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 的 class_members 可能不完整(当前模块只解析了部分字段),
# 优先从 stub.ll 加载完整定义。set_body 只能对 opaque struct 调用一次,
# 若用不完整 class_members 设置 body后续无法修正会导致 GEP 越界。
# 但本地定义的类_classes_in_progress不从 stub 加载,因为 stub 可能
# 来自同名导入类,其 vtable 状态与本地定义不同(@t.NoVTable 冲突)
import_handler: Any = self._import_handler_ref
if import_handler is not None and ClassName not in self._classes_in_progress:
try:
# 传入 source_sha1 确保从正确的 stub 文件加载完整定义
_src_sha1: str = self.class_sha1_map.get(ClassName, '')
import_handler._TryLoadStructFromStub(ClassName, self, source_sha1=_src_sha1 or None)
except Exception:
pass
struct_type = self.structs.get(ClassName, struct_type)
# 检测 stub body 中的 T* 占位类型(未特化的泛型类型参数)。
# 若 stub 使用了未特化的基类(如 GSListNode 而非 GSListNode[BasicBlock]
# 清除 _elements 让 set_body 用正确的 class_members 重新设置。
if struct_type.elements is not None and member_types:
_has_t_placeholder_post: bool = False
for _elem_post in struct_type.elements:
if isinstance(_elem_post, ir.PointerType) and isinstance(_elem_post.pointee, ir.IdentifiedStructType):
_pname_post: str = _elem_post.pointee.name
_short_post: str = _pname_post.rsplit('.', 1)[-1] if '.' in _pname_post else _pname_post
if _short_post == 'T':
_has_t_placeholder_post = True
break
if _has_t_placeholder_post:
struct_type._elements = None
if struct_type.elements is None:
# 防御性检查member_types 为空时不调用 set_body。
# set_body(*[]) 会设置 elements=() 使 is_opaque=False
# 后续无法再次 set_bodyllvmlite 限制),导致跨模块类型永久损坏。
# 根因register_method 在 class_members[ClassName]=[] 时立即调用
# _generate_structs此时 member_types 为空。保持 opaque 状态,
# 让后续 _TryLoadStructFromStub 能正确设置 body。
if member_types:
struct_type.set_body(*member_types)
def _create_Vtable_globals(self) -> None:
for ClassName, methods in self.class_methods.items():
if ClassName in self.Vtables:
continue
if not methods:
continue
if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes:
continue
# 跳过正在发射中的类:它们的方法列表可能还不完整(如继承方法已添加但自有方法未添加),
# 此时创建 vtable 会导致大小不匹配。这些类的 vtable 会在其 _EmitClassLlvm 完成后
# 由 _create_vtable_for_class 显式创建,或在模块级 _create_Vtable_globals 调用中创建。
if ClassName in self._classes_in_progress:
continue
# 跨模块虚表过滤_precollect_vtable_state 会将所有 includes 的有方法类同时加入
# _shared_class_vtable 和 _shared_cross_module_vtable导致 class_vtable 与
# _cross_module_vtable_classes 内容相同,无法用以区分本模块类与跨模块类。
# _generate_structs 会为所有 class_methods 的类创建空 struct type导致 self.structs
# 也包含所有类。过滤条件是 self.functions只考虑本模块定义的函数define有函数体
# 跳过跨模块的 declare无函数体。跨模块类的 declare 通过 HandlesImports 加入
# self.functions短名如 "MemManager.alloc"),但其 is_declaration=True。
# 若只存在 declare 而无 define说明本模块未定义该类虚表应由定义模块创建。
# vtable linkage='internal',跨模块调用通过对象的 vtable 指针(首字段)完成分派,
# 不依赖本模块的 vtable 全局变量。
has_local_method: bool = False
prefix: str = f"{ClassName}."
for func_name, func_obj in self.functions.items():
if func_name.startswith(prefix):
# 跳过跨模块的 declare无函数体只考虑本模块定义的函数
if not getattr(func_obj, 'is_declaration', False):
has_local_method = True
break
if not has_local_method:
continue
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 _create_vtable_for_class(self, ClassName: str) -> None:
"""为单个类创建 vtable用于 _EmitClassLlvm 中当前类的方法已全部注册后)。"""
methods: list = self.class_methods.get(ClassName, [])
if not methods:
return
if ClassName not in self.class_vtable and ClassName not in self._cross_module_vtable_classes:
return
_vtable_name: str = self._mangle_name(f"{ClassName}_Vtable")
# 如果虚表已在导入阶段创建(方法列表不完整,缺少继承方法),删除旧虚表
if ClassName in self.Vtables:
_old_vtable = self.Vtables[ClassName]
_old_name = _old_vtable.name
if _old_name in self.module.globals:
del self.module.globals[_old_name]
# llvmlite 的 NameScope._useset 追踪所有已使用的名字,
# del module.globals[name] 不会从 _useset 移除,
# 导致再次创建同名 GlobalVariable 时 scope.register() 报 DuplicatedNameError
self.module.scope._useset.discard(_old_name)
del self.Vtables[ClassName]
# 防御性:如果全局变量已存在但不在 Vtables 字典中,也删除
if _vtable_name in self.module.globals:
del self.module.globals[_vtable_name]
self.module.scope._useset.discard(_vtable_name)
VtableType: ir.ArrayType = ir.ArrayType(ir.PointerType(ir.IntType(8)), len(methods))
Vtable: ir.GlobalVariable = ir.GlobalVariable(self.module, VtableType, name=_vtable_name)
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) -> 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: bool = False
if gv.initializer is None:
needs_fix = True
elif hasattr(gv.initializer, 'constant') and isinstance(gv.initializer.constant, _Undefined):
needs_fix = True
elif isinstance(gv.initializer, ir.Constant):
if isinstance(gv.initializer.constant, list):
if any(hasattr(c, 'constant') and isinstance(c.constant, _Undefined) for c in gv.initializer.constant):
needs_fix = True
if not needs_fix:
continue
gv.initializer = ir.Constant(gv.value_type, None)
if gv_name.startswith('str_const_') or gv_name.endswith('_Vtable') or gv_name.endswith('_str'):
gv.linkage = 'internal'
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: ir.IdentifiedStructType | None = self.structs.get(ClassName)
if struct_type is None:
continue
Vtable: ir.GlobalVariable = self.Vtables[ClassName]
Vtable_entries: list[ir.Constant] = []
for MethodName in methods:
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: str | None = self.class_parent.get(ClassName)
while parent_cls:
parent_full: str = f"{parent_cls}.{short_name}"
if parent_full in self.functions:
func = self.functions[parent_full]
break
parent_cls = self.class_parent.get(parent_cls)
if func is None:
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)