a 编译器缺陷(承接 b8ed33a2):Step 4 的前置校验只在**当次** _generate_structs 生效,
漏掉"class_members 被 .vpi/stub 修正在后、struct body 冻结在前"的时序 —— 于是
一次只修好一部分槽(实测:第 3 槽修好、第 11 槽仍错),错误逐个前移。
证据链(成员槽来源明细 + 全盘 grep):
class_members[Generator] 项数=47 base=0 下标=11
声明槽类型=%"a7b68c79f39cb4d3.ExprGenFstr"*
布局 struct name='fd4cd0ec583f42b9.Generator' 元素数=47 elements[11]=i8**
且**没有任何** stub 文本里含 i8** ⇒ body 是从"当时已降级的 class_members"冻住的,
后来重载只修 class_members,改不了已冻结的 body(llvmlite set_body 只能设一次)。
修法:新增 StructGen._SyncStructBodyTypes —— 在**使用点**(_get_member_offset,
即任何 GEP 之前、成员表已在上方补齐/重载之后)按 class_members 逐槽比对,
只把**存储时必被拒绝**的槽(判据同 _MemberSlotAccepts)改回声明类型,其余元素
(含通用指针 i8* 槽)原样保留;_elements 置空后 set_body 重设(命名类型对象不变,
故已发出的 getelementptr %"name"* 不受影响)。同名类 sha1 冲突路径
(_ResolvedClass != ClassName)跳过,避免用别的同名类成员表写坏布局。
831 lines
49 KiB
Python
831 lines
49 KiB
Python
from __future__ import annotations
|
||
from typing import Any
|
||
import re
|
||
import vast as 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:
|
||
"""类型自然对齐(字节)。
|
||
|
||
与 `_get_struct_size` 同一约定:**不允许静默近似**。对齐猜错会让字段字节偏移
|
||
与 LLVM 实际布局不一致(本函数是 `_get_struct_size` 的字段偏移累加与
|
||
`_compute_field_byte_offset` 的输入),故拿不到对齐时一律响亮失败:
|
||
- opaque/未解析的 IdentifiedStructType → 曾按 ptr_size 猜;
|
||
- 未识别类型 → 曾按 4 猜。
|
||
"""
|
||
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.VectorType):
|
||
# 与 LLVM 一致:向量对齐 = 元素对齐(同 _get_struct_size 的向量口径)
|
||
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):
|
||
resolved = self._resolve_opaque_struct(llvm_type)
|
||
if resolved is not llvm_type:
|
||
return self._get_align(resolved)
|
||
if llvm_type.elements is None or len(llvm_type.elements) == 0:
|
||
raise ValueError(
|
||
f"[FATAL][__sizeof__] 结构体 '{getattr(llvm_type, 'name', llvm_type)}' "
|
||
f"布局未就绪(opaque / 未解析到定义),拒绝按指针对齐兜底 —— "
|
||
f"对齐猜错会让字段字节偏移与 LLVM 实际布局不一致(读写落到错误字段)。"
|
||
f"请先确保该结构体已注册/可从 stub 加载后再取对齐。"
|
||
)
|
||
return max((self._get_align(f) for f in llvm_type.elements), default=1)
|
||
if isinstance(llvm_type, ir.VoidType):
|
||
return 0
|
||
raise ValueError(
|
||
f"[FATAL][__sizeof__] 不支持的类型 {llvm_type}({type(llvm_type).__name__})"
|
||
f"无法计算对齐,拒绝以常数 4 兜底 —— 对齐猜错会让字段字节偏移与 LLVM 实际布局不一致。")
|
||
|
||
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:
|
||
"""类型字节尺寸(含字段对齐/填充)。
|
||
|
||
**不允许静默近似**:本函数的返回值会被 `X.__sizeof__()` 直接采用
|
||
(HandlesExprCall._HandleSizeofLlvm),而 memhub 的 alloc 又直接吃该值。
|
||
此前两处静默兜底会**少算尺寸**,进而按过小尺寸分配 → 越界写坏邻居块的
|
||
8 字节块头(块头 `(order<<1)|1` 被写成偶数 ⇒ reset_to 视为"已释放"跳过、
|
||
free 被 _is_valid_ptr 判无效而静默 no-op)⇒ 该块永久丢失 ⇒ 1 GiB 主池漏满:
|
||
- opaque/未解析的 IdentifiedStructType → 曾一律返回 ptr_size;
|
||
- 未识别类型(如 SIMD VectorType)→ 曾一律返回 4。
|
||
故尺寸拿不到时一律响亮失败(项目约定:类型信息缺失立即终止,不兜底)。
|
||
"""
|
||
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.VectorType):
|
||
# 与 LLVM 一致:元素尺寸 × 元素数,再向上取到 2 的幂(<3 x i32> = 16 字节)
|
||
elem_size: int = self._get_struct_size(llvm_type.element)
|
||
lanes: int = llvm_type.count
|
||
padded: int = 1
|
||
while padded < lanes:
|
||
padded = padded << 1
|
||
return elem_size * padded
|
||
if isinstance(llvm_type, ir.LiteralStructType):
|
||
total: int = 0
|
||
max_align: int = 1
|
||
# llvmlite 的 LiteralStructType 只有 `.elements`(**没有** `.fields`):
|
||
# 旧代码写 `.fields` 必然 AttributeError,尺寸/对齐链在此静默断掉。
|
||
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
|
||
if isinstance(llvm_type, ir.IdentifiedStructType):
|
||
# 尝试解析 opaque struct 为已注册的版本
|
||
resolved = self._resolve_opaque_struct(llvm_type)
|
||
if resolved is not llvm_type:
|
||
return self._get_struct_size(resolved)
|
||
if llvm_type.elements is None or len(llvm_type.elements) == 0:
|
||
raise ValueError(
|
||
f"[FATAL][__sizeof__] 结构体 '{getattr(llvm_type, 'name', llvm_type)}' "
|
||
f"布局未就绪(opaque / 未解析到定义),拒绝按指针大小兜底 —— "
|
||
f"近似会少算尺寸,调用方(memhub alloc)按过小尺寸分配并越界写坏邻居块头。"
|
||
f"请先确保该结构体已注册/可从 stub 加载后再取尺寸。"
|
||
)
|
||
total2: int = 0
|
||
max_align2: int = 1
|
||
for f in llvm_type.elements:
|
||
fa2: int = self._get_align(f)
|
||
fs2: int = self._get_struct_size(f)
|
||
max_align2 = max(max_align2, fa2)
|
||
if fa2 > 1:
|
||
total2 = (total2 + fa2 - 1) // fa2 * fa2
|
||
total2 += fs2
|
||
if max_align2 > 1:
|
||
total2 = (total2 + max_align2 - 1) // max_align2 * max_align2
|
||
return total2
|
||
raise ValueError(
|
||
f"[FATAL][__sizeof__] 不支持的类型 {llvm_type}({type(llvm_type).__name__})"
|
||
f"无法计算尺寸,拒绝以常数兜底 —— 近似会少算尺寸并越界写坏内存池块头。"
|
||
)
|
||
|
||
@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()
|
||
# 函数级 DWARF(--dwarf / --asan):把 Module 落成 .ll 文本之前补模块级
|
||
# !llvm.dbg.cu 与 !llvm.module.flags(Debug Info Version=3);未启用时
|
||
# _GetDebugInfo() 返回 None,不做任何事(零影响)。
|
||
_DbgInfo = self._GetDebugInfo()
|
||
if _DbgInfo is not None:
|
||
_DbgInfo.Finalize()
|
||
# Ctrl+C 调用栈(--traceback):同样是"落成 .ll 文本之前"的模块级收尾——
|
||
# 当本模块就是 includes/traceback.vp 时,注入 @llvm.global_ctors 构造器调用
|
||
# 其 Install()(见 BaseGen._RegisterTracebackInstallViaCtor)。未启用/非该模块
|
||
# 时 traceback_ctor=False,不做任何事(零影响)。
|
||
if self.traceback_ctor:
|
||
self._RegisterTracebackInstallViaCtor()
|
||
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)
|
||
# 协程帧结构体兜底(M1):帧注册进 Gen.structs 时上面已输出;
|
||
# 未注册(被 _generate_structs 清空)时这里补齐定义,避免
|
||
# getelementptr base element must be sized。
|
||
coro_frames: dict = getattr(self, '_coro_frame_types', None) or {}
|
||
for _cf_name, _cf_ty in coro_frames.items():
|
||
if _cf_name in struct_names:
|
||
continue
|
||
if isinstance(_cf_ty, ir.IdentifiedStructType) and _cf_ty.elements:
|
||
_cf_sname: str = _cf_ty.name
|
||
_cf_ir: str = f'%"{_cf_sname}"' if (_cf_sname[0].isdigit() or "." in _cf_sname) else f'%{_cf_sname}'
|
||
struct_defs.append(f'{_cf_ir} = type {{ {", ".join(str(e) for e in _cf_ty.elements)} }}')
|
||
struct_names.add(_cf_sname)
|
||
if struct_defs:
|
||
lines: list[str] = ir_text.split('\n')
|
||
# 预计算全部 "= type" 定义行前缀(一次性),用 str.startswith(tuple)
|
||
# 在 C 层批量比较,替代原 O(lines × structs × patterns) 的 Python 嵌套
|
||
# 循环(PROF: finalize tottime 84.8s + startswith 4114 万次 46.9s)。
|
||
name_prefixes: list[str] = []
|
||
for name in struct_names:
|
||
if name[0].isdigit() or '.' in name or not name.replace('_', '').replace('.', '').isalnum():
|
||
name_prefixes.append(f'%"{name}" = type')
|
||
name_prefixes.append(f'%"{name}"=type')
|
||
name_prefixes.append(f'%{name} = type')
|
||
name_prefixes.append(f'%{name}=type')
|
||
else:
|
||
name_prefixes.append(f'%{name} = type')
|
||
name_prefixes.append(f'%{name}= type')
|
||
name_prefixes.append(f'%{name}=type')
|
||
prefixes_tuple: tuple[str, ...] = tuple(name_prefixes)
|
||
filtered: list[str] = []
|
||
for line in lines:
|
||
if not line.strip().startswith(prefixes_tuple):
|
||
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_head = ir_text[:insert_pos + 1]
|
||
_ir_tail = ir_text[insert_pos + 1:]
|
||
ir_text = _ir_head + struct_block + _ir_tail
|
||
# 仅含特殊字符(数字开头或含点)的 struct 名需要加引号:
|
||
# 合并为单个正则一次扫描全文本,替代逐 name 各自 re.sub(每个 name
|
||
# 一次 O(text) 扫描)。lookahead 边界排除保证各备选互斥,语义等价。
|
||
special_names: list[str] = [n for n in struct_names if n[0].isdigit() or '.' in n]
|
||
if special_names:
|
||
ir_text = re.sub(
|
||
r'%(' + '|'.join(re.escape(n) for n in special_names) + r')(?=[^a-zA-Z0-9_$\.]|$)',
|
||
lambda m: r'%"' + m.group(1) + r'"',
|
||
ir_text
|
||
)
|
||
|
||
return ir_text
|
||
|
||
def _MemberSlotAccepts(self, Declared: Any, Slot: Any) -> bool:
|
||
"""声明类型能否**隐式写进**该 struct 槽(判据与存储侧同一套)。
|
||
|
||
用于判定已冻结的 struct body 是否与 `class_members` 自洽。判定放宽到与
|
||
存储侧一致,避免误清:通用指针槽(i8*/void*)照旧放行(历史 stub 普遍
|
||
如此),继承上转/数组退让亦放行;只有**存储时必被拒绝**的组合——层数
|
||
不同、指针与非指针混位——才判为不一致,触发重建。
|
||
"""
|
||
if Declared is None or Slot is None:
|
||
return True
|
||
if Declared == Slot or str(Declared) == str(Slot):
|
||
return True
|
||
_d_ptr: bool = isinstance(Declared, ir.PointerType)
|
||
_s_ptr: bool = isinstance(Slot, ir.PointerType)
|
||
if _d_ptr != _s_ptr:
|
||
return False
|
||
if not _d_ptr:
|
||
# 数值/浮点宽度差异不在本次收紧范围:保持既有行为(不清 body)。
|
||
return True
|
||
try:
|
||
Allowed, _Reason = self._ClassifyPtrImplicitConvert(Declared, Slot)
|
||
return bool(Allowed)
|
||
except Exception:
|
||
# 判据不可用(缺上下文)时保守放行,避免误清已正确的布局。
|
||
return True
|
||
|
||
def _SyncStructBodyTypes(self, ClassName: str | None) -> None:
|
||
"""把 struct body 中与 `class_members` 声明**不兼容**的槽改回声明类型(就地修复)。
|
||
|
||
背景:llvmlite 的 `set_body` 只能设一次。若某个早期 pass 在 `class_members`
|
||
尚未被 .vpi / stub 修正、类型已降级(如 `i8**` 顶替 `%X*`)时就把 body 冻住,
|
||
错位会**永久留存** —— 后续重载只修 `class_members`,不动 body
|
||
(现场:Generator 第 3/11 槽;一次修好一槽、下一槽仍错,正是时序随机)。
|
||
Step 4 的前置校验只在**当次** `_generate_structs` 生效,漏"修正晚于冻结"的时序,
|
||
故在**使用点**(成员偏移查询,即任何 GEP 之前)再校一次并就地修复:
|
||
|
||
- 只替换**存储时必被拒绝**的槽(判据与存储侧同一套 `_MemberSlotAccepts`),
|
||
其余元素(含通用指针 i8* 槽)原样保留 —— 不做整表重建,避免丢 stub 侧信息;
|
||
- `_elements` 置空后 `set_body` 重设:命名类型对象不变,故已发出的
|
||
`getelementptr %"name"*` 不受影响。
|
||
|
||
LLVM 具名类型只有一份定义,重设 body 后打印即为修正后的布局,故在模块落盘前
|
||
修复是安全的;越早(首次字段访问)修复越干净。
|
||
"""
|
||
if not ClassName:
|
||
return
|
||
_st: Any = self.structs.get(ClassName)
|
||
if not isinstance(_st, ir.IdentifiedStructType) or _st.elements is None:
|
||
return
|
||
_members: list = self.class_members.get(ClassName) or []
|
||
if not _members:
|
||
return
|
||
_base: int = self._member_base(ClassName)
|
||
_elems: list = list(_st.elements)
|
||
_changed: bool = False
|
||
for _i, _item in enumerate(_members):
|
||
_j: int = _base + _i
|
||
if _j >= len(_elems):
|
||
break
|
||
_decl: Any = _item[1] if isinstance(_item, tuple) and len(_item) >= 2 else None
|
||
if _decl is not None and not self._MemberSlotAccepts(_decl, _elems[_j]):
|
||
_elems[_j] = _decl
|
||
_changed = True
|
||
if not _changed:
|
||
return
|
||
_st._elements = None
|
||
_st.set_body(*_elems)
|
||
|
||
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 not _imported_sha1:
|
||
# 兜底查全局类→模块映射:class_sha1_map 可能因共享 class_methods
|
||
# 跨文件泄漏而缺失条目(LlvmGenerator 共享赋值),此时若处于
|
||
# 泛型特化窗口(module_sha1 被切为模板定义模块如 _list 的 sha1),
|
||
# _mangle_name 会用错误前缀注册其它模块的类
|
||
# (7cadfe07e983fd90.Translator 跨模块类型错位根因)。
|
||
# _struct_sha1_map 由 Phase2 从 vpi 扫描构建,含全部类的正确模块映射。
|
||
_imported_sha1 = self._struct_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
|
||
# 逐元素类型一致性(治本):仅比"个数 / 首元素是 vtable 指针 / T 占位"
|
||
# 会漏掉**类型错位**的已冻结 body —— 现场 Generator:47 个元素个数正确、
|
||
# 元素名字也全对,但第 4 槽是 i8** 而 class_members 声明
|
||
# %"d827f3045bd28467.TypeGenCDef"*,个数命中即被当作"完整"直接 continue;
|
||
# 而 llvmlite 的 set_body 只能设一次 ⇒ 错布局被永久冻结(后续 .vpi 重载
|
||
# 只修 class_members,改不了 body)⇒ 赋值时报"层数不同"。
|
||
# 判据与存储侧同一套(_MemberSlotAccepts → _ClassifyPtrImplicitConvert):
|
||
# 声明类型**能隐式写进该槽**才算一致 —— 通用指针槽(i8*)照旧放行,不误清。
|
||
_slot_types_ok: bool = True
|
||
_members_pre: list = self.class_members.get(ClassName, [])
|
||
if _members_pre:
|
||
_base_pre: int = 1 if _has_vtable_precheck else 0
|
||
_elems_pre: list = list(existing_st.elements)
|
||
for _i_pre, _item_pre in enumerate(_members_pre):
|
||
_j_pre: int = _base_pre + _i_pre
|
||
if _j_pre >= len(_elems_pre):
|
||
break
|
||
_decl_pre: Any = _item_pre[1] if isinstance(_item_pre, tuple) and len(_item_pre) >= 2 else None
|
||
if not self._MemberSlotAccepts(_decl_pre, _elems_pre[_j_pre]):
|
||
_slot_types_ok = False
|
||
break
|
||
if (len(existing_st.elements) >= _expected_count_pre and _vtable_first_ok
|
||
and not _has_t_placeholder_pre and _slot_types_ok):
|
||
if ClassName in self.class_packed and not existing_st.packed:
|
||
existing_st.packed = True
|
||
continue
|
||
# struct body 不完整,清除 _elements 和 stub 缓存以便重新加载
|
||
existing_st._elements = None
|
||
# 同时清除 sha1 全名 key 的 _elements:
|
||
# self.structs 中可能同时存在 'Value'(短名) 和 'f9e36e2cd6fa659f.Value'(sha1全名) 两个 key,
|
||
# _TryLoadStructFromStub 调用 _get_or_create_struct 时会返回 sha1全名 key 的 struct。
|
||
# 若只清除短名 key 的 _elements,sha1全名 key 的 struct 仍保持错误 body(is_opaque=False),
|
||
# 导致 _TryLoadStructFromStub 跳过 set_body,struct 保持不完整字段数。
|
||
_imported_sha1_pre: str = self.class_sha1_map.get(ClassName, '')
|
||
if _imported_sha1_pre:
|
||
_full_key_pre: str = f"{_imported_sha1_pre}.{ClassName}"
|
||
_full_st_pre: ir.IdentifiedStructType | None = self.structs.get(_full_key_pre)
|
||
if _full_st_pre is not None and isinstance(_full_st_pre, ir.IdentifiedStructType):
|
||
_full_st_pre._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]
|
||
# 同时清除 sha1全名 key 的 stub 缓存
|
||
if _imported_sha1_pre:
|
||
_cache_key_full_pre: tuple = (id(self), f"{_imported_sha1_pre}.{ClassName}")
|
||
if _cache_key_full_pre in _import_handler_pre._struct_Load_cache:
|
||
del _import_handler_pre._struct_Load_cache[_cache_key_full_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_structs:class_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_body(llvmlite 限制),导致跨模块类型永久损坏。
|
||
# 根因: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))
|
||
# 保持默认 linkage(空字符串,带 initializer 自动打印为外部强定义
|
||
# global,llvmlite descr 规则:initializer 非空时 linkage 归一为空)。
|
||
# 2026-08-10:跨模块 isinstance 需引用 sha1.Class_Vtable 符号,
|
||
# vtable 名含模块 sha1 前缀全局唯一,外部可见不会冲突。
|
||
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))
|
||
# 默认 linkage(外部强定义),跨模块 isinstance 引用(与 _create_Vtable_globals 一致)
|
||
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
|
||
# 多继承:vtable 槽直接用完整方法名(实际定义类.方法,如 B.get_b)
|
||
func: ir.Function | None = None
|
||
if MethodName in self.functions:
|
||
func = self.functions[MethodName]
|
||
if func is None:
|
||
full_MethodName: str = f"{ClassName}.{short_name}"
|
||
if full_MethodName in self.functions:
|
||
func = self.functions[full_MethodName]
|
||
if func is None:
|
||
# 沿 MRO 祖先链查找定义类(先声明父类优先)
|
||
for anc in self._get_mro_chain(ClassName)[1:]:
|
||
parent_full: str = f"{anc}.{short_name}"
|
||
if parent_full in self.functions:
|
||
func = self.functions[parent_full]
|
||
break
|
||
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) |