重置上传,新增了多个标准库,开始 TransPyV 自举实验
This commit is contained in:
@@ -476,6 +476,7 @@ class DeclarationGenerator:
|
||||
seen_member_names: set[str] = set()
|
||||
for base in node.bases:
|
||||
base_name: str | None = None
|
||||
type_args: list[str] = []
|
||||
if isinstance(base, ast.Attribute):
|
||||
base_name = base.attr
|
||||
elif isinstance(base, ast.Name):
|
||||
@@ -485,10 +486,19 @@ class DeclarationGenerator:
|
||||
base_name = base.value.attr
|
||||
elif isinstance(base.value, ast.Name):
|
||||
base_name = base.value.id
|
||||
slice_node: ast.AST = base.slice
|
||||
if isinstance(slice_node, ast.Name):
|
||||
type_args.append(slice_node.id)
|
||||
elif isinstance(slice_node, ast.Tuple):
|
||||
for elt in slice_node.elts:
|
||||
if isinstance(elt, ast.Name):
|
||||
type_args.append(elt.id)
|
||||
if base_name and not self._is_marker_base(base_name):
|
||||
base_member_types: list[str]
|
||||
base_seen: set[str]
|
||||
base_member_types, base_seen = self._get_inherited_members(base_name)
|
||||
if type_args:
|
||||
base_member_types = self._specialize_member_types(base_member_types, type_args)
|
||||
for mt in base_member_types:
|
||||
member_types.append(mt)
|
||||
seen_member_names.update(base_seen)
|
||||
@@ -632,8 +642,124 @@ class DeclarationGenerator:
|
||||
decls.append(f'declare {ret_type} @"{method_name}"({param_str})')
|
||||
else:
|
||||
decls.append(f'declare {ret_type} @{method_name}({param_str})')
|
||||
# 为继承但未覆写的方法生成包装声明
|
||||
# 这些声明让跨模块调用能正确解析子类包装函数的签名,
|
||||
# 避免 stub 缺失导致默认 i32 返回类型 → 64 位指针截断
|
||||
decls.extend(self._generate_inherited_method_decls(node, class_name, struct_type_name))
|
||||
return decls
|
||||
|
||||
def _generate_inherited_method_decls(self, node: ast.ClassDef, child_class_name: str, child_struct_type: str) -> list[str]:
|
||||
"""为继承但未覆写的方法生成包装声明
|
||||
|
||||
在 Phase 1 stub 中声明子类继承方法的签名(与父类相同,但 self 参数为子类类型)。
|
||||
这样测试模块翻译时能从 temp stub 中获取正确的返回类型,
|
||||
避免 Phase 2 includes 翻译滞后导致跨模块调用使用默认 i32 返回类型。
|
||||
"""
|
||||
decls: list[str] = []
|
||||
# 收集子类自身定义的方法名(这些不需要生成包装,子类有自己的实现)
|
||||
seen_method_names: set[str] = set()
|
||||
for item in node.body:
|
||||
if isinstance(item, ast.FunctionDef):
|
||||
seen_method_names.add(item.name)
|
||||
|
||||
# 沿继承链收集父类方法,近祖先优先
|
||||
for base in node.bases:
|
||||
base_name: str | None = None
|
||||
if isinstance(base, ast.Attribute):
|
||||
base_name = base.attr
|
||||
elif isinstance(base, ast.Name):
|
||||
base_name = base.id
|
||||
elif isinstance(base, ast.Subscript):
|
||||
if isinstance(base.value, ast.Attribute):
|
||||
base_name = base.value.attr
|
||||
elif isinstance(base.value, ast.Name):
|
||||
base_name = base.value.id
|
||||
if not base_name or self._is_marker_base(base_name):
|
||||
continue
|
||||
self._CollectInheritedWrapperDecls(
|
||||
base_name, child_class_name, child_struct_type,
|
||||
seen_method_names, decls)
|
||||
return decls
|
||||
|
||||
def _CollectInheritedWrapperDecls(
|
||||
self, parent_name: str, child_class_name: str, child_struct_type: str,
|
||||
seen_method_names: set[str], decls: list[str]) -> None:
|
||||
"""递归收集父类及其祖先的方法,为未覆写的方法生成包装声明"""
|
||||
# 查找父类节点:先在当前 .pyi 中查找,找不到则查跨模块类定义映射
|
||||
parent_node: ast.ClassDef | None = None
|
||||
for n in ast.iter_child_nodes(self._pyi_tree):
|
||||
if isinstance(n, ast.ClassDef) and n.name == parent_name:
|
||||
parent_node = n
|
||||
break
|
||||
if parent_node is None:
|
||||
parent_node = self._cross_module_class_defs.get(parent_name)
|
||||
if parent_node is None:
|
||||
return
|
||||
|
||||
# 为父类的每个方法生成包装声明
|
||||
for item in parent_node.body:
|
||||
if isinstance(item, ast.FunctionDef):
|
||||
if hasattr(item, 'type_params') and item.type_params:
|
||||
continue
|
||||
method_name: str = item.name
|
||||
# __before_init__ 只在自身类生成,不生成继承包装
|
||||
if method_name == '__before_init__':
|
||||
continue
|
||||
# 跳过子类已覆写的方法,以及已处理的祖先方法
|
||||
if method_name in seen_method_names:
|
||||
continue
|
||||
seen_method_names.add(method_name)
|
||||
|
||||
# 构建包装方法名:{module_sha1}.{child_class}.{method_name}
|
||||
wrapper_name: str = f'{child_class_name}.{method_name}'
|
||||
if self.module_sha1:
|
||||
wrapper_name = f"{self.module_sha1}.{wrapper_name}"
|
||||
|
||||
# 解析返回类型(与父类方法相同)
|
||||
ret_type: str = self._get_type_str(item.returns) if item.returns else 'void'
|
||||
if not ret_type:
|
||||
ret_type = 'void'
|
||||
elif ret_type == 'i8*':
|
||||
if item.returns is None:
|
||||
ret_type = 'void'
|
||||
|
||||
# 构建参数列表:第一个参数(self)替换为子类类型,其余与父类相同
|
||||
params: list[str] = []
|
||||
for arg_idx, arg in enumerate(item.args.args):
|
||||
arg_type: str
|
||||
if arg_idx == 0 and arg.arg == 'self':
|
||||
arg_type = f'{child_struct_type}*'
|
||||
else:
|
||||
if arg.annotation:
|
||||
arg_type = self._get_type_str(arg.annotation)
|
||||
else:
|
||||
arg_type = 'i8*'
|
||||
arg_type = self._decay_array_to_ptr(arg_type)
|
||||
params.append(arg_type)
|
||||
|
||||
param_str: str = ', '.join(params) if params else ''
|
||||
if wrapper_name[0].isdigit():
|
||||
decls.append(f'declare {ret_type} @"{wrapper_name}"({param_str})')
|
||||
else:
|
||||
decls.append(f'declare {ret_type} @{wrapper_name}({param_str})')
|
||||
|
||||
# 递归处理祖先类
|
||||
for base in parent_node.bases:
|
||||
base_name: str | None = None
|
||||
if isinstance(base, ast.Attribute):
|
||||
base_name = base.attr
|
||||
elif isinstance(base, ast.Name):
|
||||
base_name = base.id
|
||||
elif isinstance(base, ast.Subscript):
|
||||
if isinstance(base.value, ast.Attribute):
|
||||
base_name = base.value.attr
|
||||
elif isinstance(base.value, ast.Name):
|
||||
base_name = base.value.id
|
||||
if base_name and not self._is_marker_base(base_name):
|
||||
self._CollectInheritedWrapperDecls(
|
||||
base_name, child_class_name, child_struct_type,
|
||||
seen_method_names, decls)
|
||||
|
||||
def _get_inherited_members(self, base_name: str) -> tuple[list[str], set[str]]:
|
||||
member_types: list[str] = []
|
||||
seen_names: set[str] = set()
|
||||
@@ -675,6 +801,36 @@ class DeclarationGenerator:
|
||||
seen_names.add(stmt.targets[0].attr)
|
||||
return member_types, seen_names
|
||||
|
||||
def _specialize_member_types(self, member_types: list[str], type_args: list[str]) -> list[str]:
|
||||
"""将基类成员类型中的泛型参数 T 替换为具体类型参数
|
||||
|
||||
处理泛型基类继承(如 GSListNode[BasicBlock])时,基类 _get_inherited_members
|
||||
返回的成员类型中会包含未特化的 T 引用(形式为 %"SHA1.T"*)。
|
||||
|
||||
替换策略:使用 i8*(不透明指针)代替 T*,而非具体类型指针。
|
||||
原因:跨模块场景中,具体类型指针的 SHA1 前缀可能与导入模块不一致,
|
||||
导致 TransPyC 类型转换失败。i8* 作为通用指针类型,可安全赋值给
|
||||
任何 Class | t.CPtr 注解的变量,运行时行为与 T* 相同(都是指针)。
|
||||
|
||||
Args:
|
||||
member_types: 基类成员类型字符串列表
|
||||
type_args: 类型参数名列表(如 ['BasicBlock'])
|
||||
|
||||
Returns:
|
||||
特化后的成员类型字符串列表
|
||||
"""
|
||||
if not type_args:
|
||||
return member_types
|
||||
result: list[str] = []
|
||||
for mt in member_types:
|
||||
new_mt: str = mt
|
||||
# 将 %"SHA1.T"* 替换为 i8*(不透明指针)
|
||||
new_mt = re.sub(r'%"[a-f0-9]+\.T"\*', 'i8*', new_mt)
|
||||
# 将 %"SHA1.T"(非指针,如 embedded struct)替换为 i8*
|
||||
new_mt = re.sub(r'%"[a-f0-9]+\.T"', 'i8*', new_mt)
|
||||
result.append(new_mt)
|
||||
return result
|
||||
|
||||
def _llvm_type_size_str(self, type_str: str) -> int:
|
||||
"""估算 LLVM 类型字符串的大小(字节),用于 REnum 变体大小比较
|
||||
|
||||
@@ -839,6 +995,18 @@ class DeclarationGenerator:
|
||||
base: str = self._get_type_str(annotation.value)
|
||||
if base == 'i8*' and isinstance(annotation.slice, ast.Constant):
|
||||
return f'[{self._get_const_int(annotation.slice)} x i8]'
|
||||
# 处理 t.CPtr[Type] 语法(指向 Type 的指针)
|
||||
# 例如: t.CPtr[t.CPtr] -> i8** (void**), t.CPtr[t.CInt] -> i32* (int*)
|
||||
# t.CPtr[t.CPtr[t.CInt]] -> i32** (int**)
|
||||
ValueIsCPtr: bool = (
|
||||
(isinstance(annotation.value, ast.Attribute) and annotation.value.attr == 'CPtr')
|
||||
or (isinstance(annotation.value, ast.Name) and annotation.value.id == 'CPtr')
|
||||
)
|
||||
if ValueIsCPtr and isinstance(annotation.slice, (ast.Attribute, ast.Name, ast.Subscript)):
|
||||
slice_type: str = self._get_type_str(annotation.slice, embedded=True)
|
||||
if slice_type and slice_type != 'void':
|
||||
return f'{slice_type}*'
|
||||
return 'i8*'
|
||||
if isinstance(annotation.slice, ast.Constant) and isinstance(annotation.slice.value, int):
|
||||
return f'[{annotation.slice.value} x {base}]'
|
||||
# 处理 t.CArray[elem_type, count] 注解 → [count x elem_type]
|
||||
|
||||
@@ -537,12 +537,32 @@ class ClassHandle(BaseHandle):
|
||||
Gen.class_members[ClassName] = inherited + Gen.class_members[ClassName]
|
||||
if ParentClass in Gen.class_methods:
|
||||
parent_methods: list = list(Gen.class_methods[ParentClass])
|
||||
# 构建子类已有方法映射(方法短名 -> 方法全名)
|
||||
child_method_map: dict[str, str] = {}
|
||||
for m in Gen.class_methods[ClassName]:
|
||||
method_name: str = m.split('.')[-1] if '.' in m else m
|
||||
child_method_map[method_name] = m
|
||||
# 父类方法在前(保证 vtable 布局一致性,子类多态分派索引正确),
|
||||
# 子类新增方法在后。子类覆盖的方法放在父类方法的位置(用子类实现)。
|
||||
new_methods: list = []
|
||||
covered_names: set[str] = set()
|
||||
for pm in parent_methods:
|
||||
method_name: str = pm.split('.')[-1] if '.' in pm else pm
|
||||
child_method: str = f"{ClassName}.{method_name}"
|
||||
if child_method not in Gen.class_methods[ClassName]:
|
||||
Gen.class_methods[ClassName].append(child_method)
|
||||
if method_name in child_method_map:
|
||||
# 子类覆盖了父类方法 — 用子类的实现,放在父类的位置
|
||||
new_methods.append(child_method_map[method_name])
|
||||
covered_names.add(method_name)
|
||||
else:
|
||||
# 父类独有方法 — 子类未覆盖,注册子类包装器
|
||||
child_method: str = f"{ClassName}.{method_name}"
|
||||
new_methods.append(child_method)
|
||||
Gen.register_method(ClassName, child_method)
|
||||
# 添加子类新增方法(不在父类中的)
|
||||
for m in Gen.class_methods[ClassName]:
|
||||
method_name: str = m.split('.')[-1] if '.' in m else m
|
||||
if method_name not in covered_names:
|
||||
new_methods.append(m)
|
||||
Gen.class_methods[ClassName] = new_methods
|
||||
# 提取首个裸字符串字面量作为结构体 __doc__ docstring
|
||||
if (Node.body and isinstance(Node.body[0], ast.Expr)
|
||||
and isinstance(Node.body[0].value, ast.Constant)
|
||||
@@ -666,7 +686,19 @@ class ClassHandle(BaseHandle):
|
||||
例如 Label 继承 Widget.place,生成 Label.place 函数,
|
||||
内部将 self 从 Label* bitcast 为 Widget*,然后调用 Widget.place。
|
||||
"""
|
||||
methods: list = Gen.class_methods.get(ClassName, [])
|
||||
# 收集本类方法 + 沿继承链收集父类方法名
|
||||
# 原代码只遍历 class_methods[ClassName],遗漏父类独有方法(如 __enter__),
|
||||
# 导致子类调用继承的方法时链接失败(undefined reference)
|
||||
methods: list = list(Gen.class_methods.get(ClassName, []))
|
||||
p: str | None = Gen.class_parent.get(ClassName) if hasattr(Gen, 'class_parent') else None
|
||||
while p:
|
||||
parent_methods: list = Gen.class_methods.get(p, [])
|
||||
for pm in parent_methods:
|
||||
pm_short: str = pm.split('.')[-1] if '.' in pm else pm
|
||||
# 避免重复:如果子类已覆写同名方法,不添加
|
||||
if not any(m.split('.')[-1] == pm_short for m in methods):
|
||||
methods.append(pm)
|
||||
p = Gen.class_parent.get(p)
|
||||
if not methods:
|
||||
return
|
||||
if ClassName not in Gen.structs:
|
||||
|
||||
@@ -792,7 +792,10 @@ class ExprBuiltinHandle(BaseHandle):
|
||||
elif dst.type.width > 64:
|
||||
dst = Gen.builder.trunc(dst, ir.IntType(64), name="trunc_memset_dst")
|
||||
dst = Gen.builder.inttoptr(dst, ir.PointerType(ir.IntType(8)), name="memset_dst_int2ptr")
|
||||
if isinstance(val.type, ir.IntType) and val.type.width != 32:
|
||||
if isinstance(val.type, ir.PointerType):
|
||||
# 0 字面量被推断为 null 指针(i8*),memset 第二参数需要 i32
|
||||
val = ir.Constant(ir.IntType(32), 0)
|
||||
elif isinstance(val.type, ir.IntType) and val.type.width != 32:
|
||||
if val.type.width < 32:
|
||||
val = Gen.builder.zext(val, ir.IntType(32), name="zext_memset_val")
|
||||
else:
|
||||
|
||||
@@ -1872,69 +1872,180 @@ class ExprCallHandle(BaseHandle):
|
||||
self._check_eh_return(result, FuncName, Gen, called_func=func)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def _has_cvtable_decorator(node: ast.ClassDef) -> bool:
|
||||
"""检查 ClassDef 是否有 @t.CVTable 装饰器(或 @CVTable)"""
|
||||
for decorator in node.decorator_list:
|
||||
if isinstance(decorator, ast.Attribute) and getattr(decorator.value, 'id', None) == 't' and decorator.attr == 'CVTable':
|
||||
return True
|
||||
if isinstance(decorator, ast.Call):
|
||||
inner = decorator.func
|
||||
if isinstance(inner, ast.Attribute) and getattr(inner.value, 'id', None) == 't' and inner.attr == 'CVTable':
|
||||
return True
|
||||
if isinstance(inner, ast.Name) and inner.id == 'CVTable':
|
||||
return True
|
||||
if isinstance(decorator, ast.Name) and decorator.id == 'CVTable':
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _has_novtable_decorator(node: ast.ClassDef) -> bool:
|
||||
"""检查 ClassDef 是否有 @t.NoVTable 装饰器"""
|
||||
for decorator in node.decorator_list:
|
||||
if isinstance(decorator, ast.Attribute) and getattr(decorator.value, 'id', None) == 't' and decorator.attr == 'NoVTable':
|
||||
return True
|
||||
if isinstance(decorator, ast.Name) and decorator.id == 'NoVTable':
|
||||
return True
|
||||
return False
|
||||
|
||||
def _try_register_vtable_ondemand(self, ClassName: str, class_sha1: str, Gen: "LlvmGeneratorMixin") -> None:
|
||||
"""按需 vtable 注册:从 .pyi stub 检查 @t.CVTable 并注册到 vtable 集合。
|
||||
|
||||
当 vcall 决策点发现 ClassName 不在 vtable 集合中时调用。
|
||||
读取 temp/{sha1}.pyi 文件,查找 ClassName 的 ClassDef,
|
||||
检查 @t.CVTable 装饰器,注册 vtable 和方法列表。
|
||||
沿继承链递归收集方法,保证 vtable 布局与 prescan 的 _EmitClassLlvm 一致:
|
||||
- 基类方法在前(固定索引,保证多态分派正确)
|
||||
- 子类新增方法在后
|
||||
- 子类覆盖的方法放在父类的位置(用子类实现)
|
||||
|
||||
与 prescan 的 _resolve_class_flags 逻辑一致:
|
||||
- 类自身有 @t.CVTable → 注册
|
||||
- 类自身有 @t.NoVTable → 不注册
|
||||
- 类继承 @t.CVTable 基类(且无 @t.NoVTable)→ 注册(自动启用 CVTable)
|
||||
"""
|
||||
try:
|
||||
import_handler = self.Trans.ImportHandler
|
||||
project_root = import_handler._find_project_root()
|
||||
pyi_path = os.path.join(project_root, 'temp', f'{class_sha1}.pyi')
|
||||
if not os.path.isfile(pyi_path):
|
||||
struct_sha1_map = getattr(Gen, '_struct_sha1_map', {})
|
||||
|
||||
# 缓存已读取的 .pyi 文件(sha1 -> class_map)
|
||||
pyi_cache: dict[str, dict[str, ast.ClassDef]] = {}
|
||||
|
||||
def load_pyi(sha1: str) -> dict[str, ast.ClassDef] | None:
|
||||
if sha1 in pyi_cache:
|
||||
return pyi_cache[sha1]
|
||||
pyi_path = os.path.join(project_root, 'temp', f'{sha1}.pyi')
|
||||
if not os.path.isfile(pyi_path):
|
||||
return None
|
||||
with open(pyi_path, 'r', encoding='utf-8') as f:
|
||||
pyi_code = f.read()
|
||||
tree = ast.parse(pyi_code)
|
||||
cmap: dict[str, ast.ClassDef] = {}
|
||||
for node in ast.iter_child_nodes(tree):
|
||||
if isinstance(node, ast.ClassDef):
|
||||
cmap[node.name] = node
|
||||
pyi_cache[sha1] = cmap
|
||||
return cmap
|
||||
|
||||
def collect_class_methods(class_name: str, sha1: str, visited: set[str]) -> tuple[list[str], bool, bool, str | None]:
|
||||
"""递归收集类的方法列表(基类方法在前,子类方法在后)。
|
||||
|
||||
Returns:
|
||||
(methods, is_cvtable, is_novtable, parent_name)
|
||||
"""
|
||||
if class_name in visited:
|
||||
return ([], False, False, None)
|
||||
visited.add(class_name)
|
||||
|
||||
class_map = load_pyi(sha1)
|
||||
if class_map is None:
|
||||
return ([], False, False, None)
|
||||
|
||||
target_node = class_map.get(class_name)
|
||||
if target_node is None:
|
||||
return ([], False, False, None)
|
||||
|
||||
is_cvtable = self._has_cvtable_decorator(target_node)
|
||||
is_novtable = self._has_novtable_decorator(target_node)
|
||||
|
||||
# 收集自身方法
|
||||
self_methods: list[str] = []
|
||||
for item in target_node.body:
|
||||
if isinstance(item, ast.FunctionDef):
|
||||
method_name = item.name
|
||||
if method_name in ('__new__', '__init__', '__before_init__'):
|
||||
continue
|
||||
if method_name == '__call__':
|
||||
self_methods.append(f"{class_name}.__call__")
|
||||
else:
|
||||
self_methods.append(f"{class_name}.{method_name}")
|
||||
|
||||
# 收集基类方法
|
||||
parent_methods: list[str] = []
|
||||
parent_name: str | None = None
|
||||
for base in target_node.bases:
|
||||
base_name: str | None = None
|
||||
if hasattr(base, 'id'):
|
||||
base_name = base.id
|
||||
elif hasattr(base, 'attr'):
|
||||
base_name = base.attr
|
||||
if not base_name or base_name in ('Object', 'CVTable', 'NoVTable', 'CStruct', 'CUnion', 'CEnum', 'REnum', 'Exception', 'Enum'):
|
||||
continue
|
||||
if parent_name is None:
|
||||
parent_name = base_name
|
||||
|
||||
# 检查同文件内的基类
|
||||
base_node = class_map.get(base_name)
|
||||
if base_node is not None:
|
||||
base_methods, base_cvtable, base_novtable, _ = collect_class_methods(base_name, sha1, visited)
|
||||
if base_novtable:
|
||||
pass # 父类是 NoVTable,不继承 vtable
|
||||
elif base_cvtable:
|
||||
is_cvtable = True
|
||||
parent_methods.extend(base_methods)
|
||||
else:
|
||||
# 跨模块基类 — 查找基类的 sha1
|
||||
base_sha1 = struct_sha1_map.get(base_name)
|
||||
if base_sha1:
|
||||
base_methods, base_cvtable, base_novtable, _ = collect_class_methods(base_name, base_sha1, visited)
|
||||
if base_novtable:
|
||||
pass
|
||||
elif base_cvtable:
|
||||
is_cvtable = True
|
||||
parent_methods.extend(base_methods)
|
||||
else:
|
||||
# 无法找到基类的 sha1
|
||||
if base_name in Gen._cross_module_novtable:
|
||||
pass # 父类是 NoVTable,不继承 vtable
|
||||
|
||||
# 合并方法列表:基类方法在前,子类方法在后
|
||||
# 子类覆盖的方法放在父类的位置
|
||||
child_method_map: dict[str, str] = {}
|
||||
for m in self_methods:
|
||||
mn = m.split('.')[-1] if '.' in m else m
|
||||
child_method_map[mn] = m
|
||||
|
||||
merged: list[str] = []
|
||||
covered_names: set[str] = set()
|
||||
for pm in parent_methods:
|
||||
mn = pm.split('.')[-1] if '.' in pm else pm
|
||||
if mn in child_method_map:
|
||||
merged.append(child_method_map[mn])
|
||||
covered_names.add(mn)
|
||||
else:
|
||||
# 父类独有方法 — 用子类名(虚分派时函数查找会沿继承链回退)
|
||||
merged.append(f"{class_name}.{mn}")
|
||||
|
||||
for m in self_methods:
|
||||
mn = m.split('.')[-1] if '.' in m else m
|
||||
if mn not in covered_names:
|
||||
merged.append(m)
|
||||
|
||||
return (merged, is_cvtable, is_novtable, parent_name)
|
||||
|
||||
methods, is_cvtable, is_novtable, parent_name = collect_class_methods(ClassName, class_sha1, set())
|
||||
|
||||
if is_novtable:
|
||||
return
|
||||
with open(pyi_path, 'r', encoding='utf-8') as f:
|
||||
pyi_code = f.read()
|
||||
pyi_tree = ast.parse(pyi_code)
|
||||
# 查找目标 ClassDef
|
||||
target_node: ast.ClassDef | None = None
|
||||
for node in ast.iter_child_nodes(pyi_tree):
|
||||
if isinstance(node, ast.ClassDef) and node.name == ClassName:
|
||||
target_node = node
|
||||
break
|
||||
if target_node is None:
|
||||
return
|
||||
# 检查 @t.CVTable 装饰器
|
||||
is_cvtable: bool = False
|
||||
for decorator in target_node.decorator_list:
|
||||
if isinstance(decorator, ast.Attribute) and getattr(decorator.value, 'id', None) == 't' and decorator.attr == 'CVTable':
|
||||
is_cvtable = True
|
||||
break
|
||||
if isinstance(decorator, ast.Call):
|
||||
inner = decorator.func
|
||||
if isinstance(inner, ast.Attribute) and getattr(inner.value, 'id', None) == 't' and inner.attr == 'CVTable':
|
||||
is_cvtable = True
|
||||
break
|
||||
if isinstance(inner, ast.Name) and inner.id == 'CVTable':
|
||||
is_cvtable = True
|
||||
break
|
||||
if isinstance(decorator, ast.Name) and decorator.id == 'CVTable':
|
||||
is_cvtable = True
|
||||
break
|
||||
if not is_cvtable:
|
||||
return
|
||||
|
||||
# 注册到 vtable 集合(共享集合)
|
||||
Gen._cross_module_vtable_classes.add(ClassName)
|
||||
Gen.class_vtable.add(ClassName)
|
||||
# 预注册方法列表(与 prescan 逻辑一致)
|
||||
if ClassName not in Gen.class_methods:
|
||||
Gen.class_methods[ClassName] = []
|
||||
for item in target_node.body:
|
||||
if isinstance(item, ast.FunctionDef):
|
||||
method_name = item.name
|
||||
# 构造函数不放入 vtable(避免子类与基类 vtable 大小不一致破坏多态分派)
|
||||
if method_name in ('__new__', '__init__', '__before_init__'):
|
||||
continue
|
||||
if method_name == '__init__':
|
||||
full_name = f"{ClassName}.__init__"
|
||||
elif method_name == '__call__':
|
||||
full_name = f"{ClassName}.__call__"
|
||||
else:
|
||||
full_name = f"{ClassName}.{method_name}"
|
||||
if full_name not in Gen.class_methods[ClassName]:
|
||||
Gen.class_methods[ClassName].append(full_name)
|
||||
# 设置方法列表(与 prescan 逻辑一致:基类方法在前)
|
||||
Gen.class_methods[ClassName] = methods
|
||||
# 设置 class_parent(用于虚分派时的函数查找回退)
|
||||
if parent_name and ClassName not in Gen.class_parent:
|
||||
Gen.class_parent[ClassName] = parent_name
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
@@ -1601,6 +1601,15 @@ class FunctionHandle(BaseHandle):
|
||||
}
|
||||
if IsExternFunc or IsStateFunc:
|
||||
return
|
||||
# 治本修复:如果函数已经有 body(blocks 不为空),跳过重复编译。
|
||||
# 否则会导致同一函数被追加第二个 entry block(llvmlite 自动重命名为 entry.1),
|
||||
# 产生非法 IR:两个 entry block + 第二个 block 无前驱成为死代码。
|
||||
# 触发场景:泛型特化路径 _EmitGenericSpecialization 先调用 _EmitFunctionForwardDeclLlvm
|
||||
# 再调用 _EmitFunctionLlvm,若特化在多个调用点被重复触发(如 list[str] 在 split/upper 等多处使用),
|
||||
# 同一 MangledName 会进入此函数两次,第二次会重复追加 entry block。
|
||||
existing_blocks: list = getattr(func, 'blocks', [])
|
||||
if existing_blocks:
|
||||
return func
|
||||
EntryBlock = func.append_basic_block(name="entry")
|
||||
Gen.builder = ir.IRBuilder(EntryBlock)
|
||||
Gen.func = func
|
||||
@@ -1612,6 +1621,15 @@ class FunctionHandle(BaseHandle):
|
||||
# 保存当前的 var_type_info,以便函数结束时恢复
|
||||
saved_var_type_info = Gen.var_type_info.copy()
|
||||
saved_var_type_assignments = Gen.var_type_assignments.copy()
|
||||
# 治本修复:保存并清空 _local_heap_ptrs / _var_to_heap_ptr。
|
||||
# 当 with 上下文中的代码(如 s1.split(','))触发内联编译 list[str].__new__ 时,
|
||||
# 若不清空,__new__ 方法会继承外层 with 的 _local_heap_ptrs(含 %call_enter 条目),
|
||||
# 方法结束时 _emit_local_heap_frees 会尝试 bitcast/free %call_enter,
|
||||
# 但该值在 __new__ 作用域中不存在 → llc 报错 'use of undefined value'。
|
||||
saved_local_heap_ptrs = list(Gen._local_heap_ptrs)
|
||||
saved_var_to_heap_ptr = dict(Gen._var_to_heap_ptr)
|
||||
Gen._local_heap_ptrs = []
|
||||
Gen._var_to_heap_ptr = {}
|
||||
# 函数内部定义的变量会在赋值时添加到 var_type_info 中
|
||||
# 这样函数内部定义的元类型变量(如 a = t.CInt32T)就能被正确处理
|
||||
for stmt in Node.body:
|
||||
@@ -1810,8 +1828,9 @@ class FunctionHandle(BaseHandle):
|
||||
Gen.var_type_info = saved_var_type_info
|
||||
Gen.var_type_assignments = saved_var_type_assignments
|
||||
Gen._stop_iter_flag_param = None
|
||||
Gen._local_heap_ptrs = []
|
||||
Gen._var_to_heap_ptr = {}
|
||||
# 恢复外层作用域的 _local_heap_ptrs / _var_to_heap_ptr
|
||||
Gen._local_heap_ptrs = saved_local_heap_ptrs
|
||||
Gen._var_to_heap_ptr = saved_var_to_heap_ptr
|
||||
Gen._variadic_info = None
|
||||
self.Trans._CurrentCpythonObjectClass = saved_cpython_class
|
||||
self.Trans.CurrentCReturnTypes = None
|
||||
|
||||
@@ -375,10 +375,22 @@ class ImportHandle(BaseHandle):
|
||||
SearchExtensions = ['.pyi', '.py']
|
||||
sub_path_base = os.path.join(parent_dir, node.module)
|
||||
found_sub = False
|
||||
# 治本修复:用包目录名(如 'json')而非 register_module_name(当前编译模块名,如 '_dict')。
|
||||
# 当 _dict.py 导入 json 包,递归处理 json/__init__.py 中的 `from .__parser import parse` 时,
|
||||
# register_module_name='_dict' 会导致 actual_module='_dict.__parser',
|
||||
# 使 _mangle_func_name 查找失败回退到 self.module_sha1,生成错误的 mangled name。
|
||||
# 包名推导优先级:
|
||||
# 1. module_name(如果它在 ModuleSha1Map 中,说明是已注册的包名,如 'json')
|
||||
# — 处理 sha1 命名的 .pyi 文件(parent_dir 是 temp 目录时)
|
||||
# 2. os.path.basename(parent_dir)(原始路径推导,如 'json')
|
||||
if module_name and module_name in Gen.ModuleSha1Map:
|
||||
pkg_basename = module_name
|
||||
else:
|
||||
pkg_basename = os.path.basename(parent_dir)
|
||||
for ext in SearchExtensions:
|
||||
candidate = sub_path_base + ext
|
||||
if os.path.isfile(candidate):
|
||||
actual_module = f"{register_module_name}.{node.module}" if register_module_name else node.module
|
||||
actual_module = f"{pkg_basename}.{node.module}" if pkg_basename else node.module
|
||||
self._RegisterSubModuleSha1(candidate, actual_module, node.module, Gen)
|
||||
if not getattr(self.Trans, '_ImportedModules', None):
|
||||
self.Trans._ImportedModules = set()
|
||||
@@ -392,7 +404,7 @@ class ImportHandle(BaseHandle):
|
||||
break
|
||||
# SHA1 map 回退
|
||||
if not found_sub:
|
||||
actual_module = f"{register_module_name}.{node.module}" if register_module_name else node.module
|
||||
actual_module = f"{pkg_basename}.{node.module}" if pkg_basename else node.module
|
||||
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
|
||||
target_sha1 = ModuleSha1Map.get(actual_module) or ModuleSha1Map.get(node.module)
|
||||
if target_sha1:
|
||||
@@ -413,12 +425,18 @@ class ImportHandle(BaseHandle):
|
||||
SearchExtensions = ['.pyi', '.py']
|
||||
# Load __init__.py to make package-level names available
|
||||
self._LoadPackageInitForRelativeImport(mod_dir, Gen, register_module_name)
|
||||
# 治本修复:用包目录名(如 'json')而非 register_module_name(当前编译模块名,如 '_dict')。
|
||||
# 同 if node.module 分支的修复逻辑。
|
||||
if module_name and module_name in Gen.ModuleSha1Map:
|
||||
pkg_basename = module_name
|
||||
else:
|
||||
pkg_basename = os.path.basename(mod_dir)
|
||||
for alias in node.names:
|
||||
found_alias = False
|
||||
for ext in SearchExtensions:
|
||||
sub_path = os.path.join(mod_dir, alias.name + ext)
|
||||
if os.path.isfile(sub_path):
|
||||
sub_ModulePath = f"{register_module_name}.{alias.name}" if register_module_name else alias.name
|
||||
sub_ModulePath = f"{pkg_basename}.{alias.name}" if pkg_basename else alias.name
|
||||
if not getattr(self.Trans, '_ImportedModules', None):
|
||||
self.Trans._ImportedModules = set()
|
||||
self.Trans._ImportedModules.add(sub_ModulePath)
|
||||
@@ -430,7 +448,7 @@ class ImportHandle(BaseHandle):
|
||||
break
|
||||
# SHA1 map 回退
|
||||
if not found_alias:
|
||||
sub_ModulePath = f"{register_module_name}.{alias.name}" if register_module_name else alias.name
|
||||
sub_ModulePath = f"{pkg_basename}.{alias.name}" if pkg_basename else alias.name
|
||||
ModuleSha1Map = getattr(Gen, 'ModuleSha1Map', {})
|
||||
target_sha1 = ModuleSha1Map.get(sub_ModulePath) or ModuleSha1Map.get(alias.name)
|
||||
if target_sha1:
|
||||
@@ -1538,6 +1556,23 @@ class ImportHandle(BaseHandle):
|
||||
Gen.class_member_bitoffsets[ClassName] = {}
|
||||
if ClassName not in Gen.class_methods:
|
||||
Gen.class_methods[ClassName] = []
|
||||
# 先计算 source_sha1,确保首次 _TryLoadStructFromStub 调用就能使用正确的 sha1
|
||||
# 优先使用传入的 source_sha1(来自 _TryLoadClassMembersFromPyi 的直接调用,
|
||||
# 当前模块未直接导入定义模块时 module_name 查找会失败,需依赖传入的 source_sha1)
|
||||
if not source_sha1:
|
||||
if actual_module_name and hasattr(Gen, 'ModuleSha1Map') and actual_module_name in Gen.ModuleSha1Map:
|
||||
source_sha1 = Gen.ModuleSha1Map[actual_module_name]
|
||||
elif module_name and hasattr(Gen, 'ModuleSha1Map') and module_name in Gen.ModuleSha1Map:
|
||||
source_sha1 = Gen.ModuleSha1Map[module_name]
|
||||
# 提前注册 struct:使用导入的 source_sha1 创建 opaque struct,
|
||||
# 避免后续 _TryLoadStructFromStub 触发嵌套编译时,StructGen 用本地 sha1
|
||||
# 创建缺少基类字段(如 GSListNode.Next)的本地类型定义。
|
||||
Gen._get_or_create_struct(ClassName, source_sha1=source_sha1, packed=IsPacked)
|
||||
# Track which module defines this class (for cross-module name mangling)
|
||||
if source_sha1:
|
||||
if not hasattr(Gen, 'class_sha1_map'):
|
||||
Gen.class_sha1_map = {}
|
||||
Gen.class_sha1_map[ClassName] = source_sha1
|
||||
# --- 预扫描预注册:修复编译时序问题 ---
|
||||
# _TryLoadStructFromStub → _parse_llvm_type → _specialize_generic_class
|
||||
# 可能触发 list[str].__new__ 编译(其中调用 pool.alloc(48)),
|
||||
@@ -1560,24 +1595,10 @@ class ImportHandle(BaseHandle):
|
||||
if _has_methods_prescan and IsCVTable:
|
||||
Gen._cross_module_vtable_classes.add(ClassName)
|
||||
Gen.class_vtable.add(ClassName)
|
||||
# 先计算 source_sha1,确保首次 _TryLoadStructFromStub 调用就能使用正确的 sha1
|
||||
# 优先使用传入的 source_sha1(来自 _TryLoadClassMembersFromPyi 的直接调用,
|
||||
# 当前模块未直接导入定义模块时 module_name 查找会失败,需依赖传入的 source_sha1)
|
||||
if not source_sha1:
|
||||
if actual_module_name and hasattr(Gen, 'ModuleSha1Map') and actual_module_name in Gen.ModuleSha1Map:
|
||||
source_sha1 = Gen.ModuleSha1Map[actual_module_name]
|
||||
elif module_name and hasattr(Gen, 'ModuleSha1Map') and module_name in Gen.ModuleSha1Map:
|
||||
source_sha1 = Gen.ModuleSha1Map[module_name]
|
||||
# 首次加载就传入 source_sha1,避免从其他模块的 output stub 中加载到错误的结构体定义
|
||||
# (如 HandlesExprCall.py 的 output stub 中 43f27dda2e5b5923.Value 只有 5 字段,
|
||||
# 而正确的 aaf8ba449d1e64c1.Value 有 6 字段)
|
||||
self._TryLoadStructFromStub(ClassName, Gen, source_sha1=source_sha1)
|
||||
# Track which module defines this class (for cross-module name mangling)
|
||||
if source_sha1:
|
||||
if not hasattr(Gen, 'class_sha1_map'):
|
||||
Gen.class_sha1_map = {}
|
||||
Gen.class_sha1_map[ClassName] = source_sha1
|
||||
Gen._get_or_create_struct(ClassName, source_sha1=source_sha1, packed=IsPacked)
|
||||
# 如果 _get_or_create_struct 因 sha1 冲突创建了新的 opaque struct,
|
||||
# 需用 source_sha1 重新加载正确的 stub body。
|
||||
if source_sha1:
|
||||
@@ -1727,11 +1748,32 @@ class ImportHandle(BaseHandle):
|
||||
# 直接从 AST 提取泛型基类名(如 GSListNode[Value] -> GSListNode),
|
||||
# 后续继承字段展平逻辑会从 .pyi 加载该基类的字段。
|
||||
if isinstance(_base.value, ast.Name):
|
||||
_base_name = _base.value.id
|
||||
_base_short_name: str = _base.value.id
|
||||
elif isinstance(_base.value, ast.Attribute):
|
||||
_base_name = _base.value.attr
|
||||
_base_short_name: str = _base.value.attr
|
||||
else:
|
||||
continue
|
||||
# 尝试手动构造特化名并检查是否已有特化 class_members。
|
||||
# 这解决了 _ResolveGenericSlice 失败但特化已通过其他路径
|
||||
# (如 _parse_llvm_type)触发的情况。特化 class_members 中
|
||||
# 的 T 已被正确替换为具体类型(如 BasicBlock),避免使用
|
||||
# 未特化的 GSListNode 导致 T* 占位类型残留。
|
||||
_slice_name: str | None = None
|
||||
if isinstance(_base.slice, ast.Name):
|
||||
_slice_name = _base.slice.id
|
||||
elif isinstance(_base.slice, ast.Attribute):
|
||||
_slice_name = _base.slice.attr
|
||||
elif isinstance(_base.slice, ast.Subscript):
|
||||
# 嵌套泛型(如 GSList[GSListNode[T]]),暂不处理
|
||||
pass
|
||||
_manual_spec_name: str | None = None
|
||||
if _slice_name is not None:
|
||||
_manual_spec_name = f"{_base_short_name}[{_slice_name}]"
|
||||
if _manual_spec_name is not None and _manual_spec_name in Gen.class_members:
|
||||
# 特化 class_members 已存在,直接使用(T 已被替换)
|
||||
_base_name = _manual_spec_name
|
||||
else:
|
||||
_base_name = _base_short_name
|
||||
else:
|
||||
continue
|
||||
if _base_name == ClassName:
|
||||
@@ -1960,6 +2002,17 @@ class ImportHandle(BaseHandle):
|
||||
st.set_body(*elem_types)
|
||||
if is_packed:
|
||||
Gen.class_packed.add(class_name)
|
||||
# 同步设置短名 struct 的 body:当存在 sha1 冲突时,_get_or_create_struct
|
||||
# 返回 full_key struct,但代码可能通过短名引用旧 struct(由 setup_from_symbol_table
|
||||
# 早期创建的 opaque 占位符,使用本地 sha1 前缀)。需要同步设置短名 struct
|
||||
# 的 body,确保 GEP 指令能正确访问字段(修复跨模块类型定义冲突导致的
|
||||
# 字段索引错位问题)。
|
||||
short_st = Gen.structs.get(class_name)
|
||||
if short_st is not None and short_st is not st and isinstance(short_st, ir.IdentifiedStructType) and short_st.is_opaque:
|
||||
try:
|
||||
short_st.set_body(*elem_types)
|
||||
except Exception:
|
||||
pass # set_body 可能因已设置而失败,忽略
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
@@ -2028,48 +2081,75 @@ class ImportHandle(BaseHandle):
|
||||
return self.Trans._BuildScalarConstantUnified(value_node, target_type, Gen)
|
||||
|
||||
def _LookupStubFuncType(self, func_name: str, Gen: LlvmGeneratorMixin) -> ir.FunctionType | None:
|
||||
"""从 stub.ll 文件中查找指定函数的 LLVM 类型"""
|
||||
"""从 stub.ll 文件中查找指定函数的 LLVM 类型
|
||||
|
||||
扫描 output/ 和 temp/ 两个目录的 .stub.ll 文件。
|
||||
关键修复:output/(Phase 2 完整结果)必须覆盖 temp/(Phase 1 不完整结果),
|
||||
否则继承包装方法(在 Phase 2 的 _generate_inherited_method_wrappers 中生成)
|
||||
将无法被解析,导致跨模块调用使用默认 i32 返回类型 → 64 位指针截断。
|
||||
"""
|
||||
|
||||
if not getattr(self, '_stub_func_cache', None):
|
||||
self._stub_func_cache = {}
|
||||
|
||||
|
||||
ProjectRoot = self._find_project_root()
|
||||
temp_dir = os.path.join(ProjectRoot, 'temp')
|
||||
|
||||
if not os.path.isdir(temp_dir):
|
||||
output_dir = os.path.join(ProjectRoot, 'output')
|
||||
|
||||
# 文件数签名:检测 stub 新增(增量编译时 output 逐步填充完整签名)
|
||||
output_count = sum(1 for f in os.listdir(output_dir) if f.endswith('.stub.ll')) if os.path.isdir(output_dir) else 0
|
||||
temp_count = sum(1 for f in os.listdir(temp_dir) if f.endswith('.stub.ll')) if os.path.isdir(temp_dir) else 0
|
||||
signature = (output_count, temp_count)
|
||||
if getattr(self, '_stub_func_cache_signature', None) != signature or not self._stub_func_cache:
|
||||
# 签名变化或缓存为空,重建缓存
|
||||
self._stub_func_cache = {}
|
||||
self._stub_func_cache_signature = signature
|
||||
|
||||
if not os.path.isdir(temp_dir) and not os.path.isdir(output_dir):
|
||||
return None
|
||||
|
||||
|
||||
if func_name not in self._stub_func_cache:
|
||||
for filename in os.listdir(temp_dir):
|
||||
if not filename.endswith('.stub.ll'):
|
||||
# 先扫描 temp/(Phase 1,不完整签名),再扫描 output/(Phase 2,完整签名)覆盖之
|
||||
# 这样 output 中存在的继承包装方法会覆盖 temp 中的同名旧声明(若有),
|
||||
# 也填补 temp 中缺失的函数声明
|
||||
for scan_dir in [temp_dir, output_dir]:
|
||||
if not os.path.isdir(scan_dir):
|
||||
continue
|
||||
|
||||
stub_path = os.path.join(temp_dir, filename)
|
||||
source_sha1 = filename.replace('.stub.ll', '')
|
||||
try:
|
||||
with open(stub_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
for line in content.splitlines():
|
||||
stripped = line.strip()
|
||||
if not stripped.startswith('declare '):
|
||||
continue
|
||||
|
||||
name_match = stripped.split('@', 1)
|
||||
if len(name_match) < 2:
|
||||
continue
|
||||
|
||||
stub_func_name = name_match[1].split('(', 1)[0].strip().strip('"')
|
||||
|
||||
match = re.match(r'declare\s+(.+?)\s+@("?[\w.]+"?)\s*\((.*)\)$', stripped)
|
||||
if match:
|
||||
stub_ret = match.group(1).strip()
|
||||
stub_params = match.group(3).strip()
|
||||
self._stub_func_cache[stub_func_name] = (stub_ret, stub_params, '...' in stub_params, source_sha1)
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"处理导入失败: {_e}", "Exception")
|
||||
for filename in os.listdir(scan_dir):
|
||||
if not filename.endswith('.stub.ll'):
|
||||
continue
|
||||
|
||||
stub_path = os.path.join(scan_dir, filename)
|
||||
# 预检查文件存在性:os.listdir 与 open 之间文件可能被并发写入删除
|
||||
if not os.path.isfile(stub_path):
|
||||
continue
|
||||
source_sha1 = filename.replace('.stub.ll', '')
|
||||
try:
|
||||
with open(stub_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
for line in content.splitlines():
|
||||
stripped = line.strip()
|
||||
if not stripped.startswith('declare '):
|
||||
continue
|
||||
|
||||
name_match = stripped.split('@', 1)
|
||||
if len(name_match) < 2:
|
||||
continue
|
||||
|
||||
stub_func_name = name_match[1].split('(', 1)[0].strip().strip('"')
|
||||
|
||||
match = re.match(r'declare\s+(.+?)\s+@("?[\w.]+"?)\s*\((.*)\)$', stripped)
|
||||
if match:
|
||||
stub_ret = match.group(1).strip()
|
||||
stub_params = match.group(3).strip()
|
||||
self._stub_func_cache[stub_func_name] = (stub_ret, stub_params, '...' in stub_params, source_sha1)
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
except Exception as _e:
|
||||
if _config_mode == "strict":
|
||||
raise
|
||||
_vlog().warning(f"处理导入失败: {_e}", "Exception")
|
||||
|
||||
if func_name not in self._stub_func_cache:
|
||||
return None
|
||||
@@ -2110,7 +2190,8 @@ class ImportHandle(BaseHandle):
|
||||
def _strip_llvm_param_name(self, param_str: str) -> str:
|
||||
"""剥离 LLVM IR 参数字符串中的参数名,仅保留类型部分"""
|
||||
param_str = param_str.strip()
|
||||
result = re.sub(r'\s+%[\w.]+\s*$', '', param_str)
|
||||
# 支持 %name 和 %"quoted.name" 两种参数名形式
|
||||
result = re.sub(r'\s+%("[^"]*"|[\w.]+)\s*$', '', param_str)
|
||||
return result.strip()
|
||||
|
||||
def _parse_simple_llvm_type(self, type_str: str) -> ir.Type | None:
|
||||
@@ -2573,6 +2654,12 @@ class ImportHandle(BaseHandle):
|
||||
existing = Gen.structs.get(struct_name)
|
||||
if existing is not None:
|
||||
return existing
|
||||
# 尝试用 source_sha1 前缀的全名查找
|
||||
if actual_source_sha1:
|
||||
full_key = f"{actual_source_sha1}.{struct_name}"
|
||||
existing_full = Gen.structs.get(full_key)
|
||||
if existing_full is not None:
|
||||
return existing_full
|
||||
return None
|
||||
return ir.IntType(32)
|
||||
|
||||
|
||||
@@ -856,9 +856,10 @@ class HandlesTypeMerge(BaseHandle):
|
||||
if TypeItem.OriginalType:
|
||||
Result.OriginalType = TypeItem.OriginalType
|
||||
continue
|
||||
# 统计 t.CPtr(CVoid + PtrCount=1)
|
||||
# 统计 t.CPtr(CVoid + PtrCount>0)
|
||||
# 注意: t.CPtr[t.CPtr] 的 PtrCount=2(双重指针),需要完整累加
|
||||
if TypeItem.PtrCount > 0 and TypeItem.BaseType and (TypeItem.BaseType is t.CVoid or isinstance(TypeItem.BaseType, t.CVoid)):
|
||||
cptr_count += 1
|
||||
cptr_count += TypeItem.PtrCount
|
||||
# BaseType 保持不变,只计数,后续统一累加
|
||||
if TypeItem.IsRenum and TypeItem.Name:
|
||||
Result.IsRenum = True
|
||||
|
||||
@@ -8,6 +8,28 @@ import llvmlite.ir as ir
|
||||
|
||||
|
||||
class WithHandle(BaseHandle):
|
||||
def _ResolveInheritedMethod(self, ClassName: str, MethodName: str, Gen: "Translator.LlvmGen") -> tuple[str | None, "ir.Function | None"]:
|
||||
"""沿继承链查找方法,返回 (定义方法的类名, 函数对象)
|
||||
|
||||
当子类未覆写 __enter__/__exit__ 等方法时,沿 Gen.class_parent 链查找父类实现。
|
||||
_generate_inherited_method_wrappers 只为 class_methods[ClassName] 中的方法生成包装,
|
||||
不包括父类独有方法,因此 with 语句需要单独处理继承查找。
|
||||
"""
|
||||
# 先检查子类自身
|
||||
FullName: str = f'{ClassName}.{MethodName}'
|
||||
func = Gen._find_function(FullName) if hasattr(Gen, '_find_function') else Gen.functions.get(FullName)
|
||||
if func:
|
||||
return (ClassName, func)
|
||||
# 沿继承链查找
|
||||
p: str | None = Gen.class_parent.get(ClassName) if hasattr(Gen, 'class_parent') else None
|
||||
while p:
|
||||
parent_full: str = f'{p}.{MethodName}'
|
||||
parent_func = Gen._find_function(parent_full) if hasattr(Gen, '_find_function') else Gen.functions.get(parent_full)
|
||||
if parent_func:
|
||||
return (p, parent_func)
|
||||
p = Gen.class_parent.get(p)
|
||||
return (None, None)
|
||||
|
||||
def _HandleWithLlvm(self, Node: ast.With) -> None:
|
||||
Gen: "Translator.LlvmGen" = self.Trans.LlvmGen
|
||||
for item in Node.items:
|
||||
@@ -60,10 +82,16 @@ class WithHandle(BaseHandle):
|
||||
ctx_is_var_ref: bool = isinstance(context_expr, ast.Name)
|
||||
enter_result: ir.Value | None = None
|
||||
if ClassName:
|
||||
EnterFuncName: str = f'{ClassName}.__enter__'
|
||||
if EnterFuncName in Gen.functions:
|
||||
# 沿继承链查找 __enter__(子类可能未覆写,使用父类实现)
|
||||
enter_class, enter_func = self._ResolveInheritedMethod(ClassName, '__enter__', Gen)
|
||||
if enter_func is not None:
|
||||
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
|
||||
enter_call: ir.CallInstr = Gen.builder.call(Gen.functions[EnterFuncName], [ctx_Loaded], name="call_enter")
|
||||
# 父类方法需要 self 为父类指针类型,bitcast 子类指针
|
||||
if enter_class != ClassName and enter_class in Gen.structs:
|
||||
parent_ptr_type = ir.PointerType(Gen.structs[enter_class])
|
||||
if ctx_Loaded.type != parent_ptr_type:
|
||||
ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_enter_self")
|
||||
enter_call: ir.CallInstr = Gen.builder.call(enter_func, [ctx_Loaded], name="call_enter")
|
||||
enter_result = enter_call
|
||||
if isinstance(enter_call.type, ir.PointerType):
|
||||
pointee: ir.Type = enter_call.type.pointee
|
||||
@@ -139,10 +167,16 @@ class WithHandle(BaseHandle):
|
||||
if Gen._with_provides_stack:
|
||||
Gen._with_provides_stack.pop()
|
||||
if ClassName:
|
||||
ExitFuncName: str = f'{ClassName}.__exit__'
|
||||
if ExitFuncName in Gen.functions:
|
||||
# 沿继承链查找 __exit__(子类可能未覆写,使用父类实现)
|
||||
exit_class, exit_func = self._ResolveInheritedMethod(ClassName, '__exit__', Gen)
|
||||
if exit_func is not None:
|
||||
ctx_Loaded: ir.Value = Gen._load(ctx_alloca, name="__with_ctx")
|
||||
Gen.builder.call(Gen.functions[ExitFuncName], [ctx_Loaded], name="call_exit")
|
||||
# 父类方法需要 self 为父类指针类型,bitcast 子类指针
|
||||
if exit_class != ClassName and exit_class in Gen.structs:
|
||||
parent_ptr_type = ir.PointerType(Gen.structs[exit_class])
|
||||
if ctx_Loaded.type != parent_ptr_type:
|
||||
ctx_Loaded = Gen.builder.bitcast(ctx_Loaded, parent_ptr_type, name="cast_exit_self")
|
||||
Gen.builder.call(exit_func, [ctx_Loaded], name="call_exit")
|
||||
Gen._unregister_local_heap_ptr(original_ctx_val)
|
||||
if ctx_val is not original_ctx_val:
|
||||
Gen._unregister_local_heap_ptr(ctx_val)
|
||||
|
||||
@@ -389,12 +389,24 @@ class BaseGenMixin:
|
||||
return int(llvm_str[1:])
|
||||
|
||||
# 4. 特殊名称(非整数类型,但需要标记为 typedef 以跳过 opaque 定义)
|
||||
# 注意:如果 name 已注册为 struct(用户定义了同名 class,如 includes/_dict.py 中的 dict),
|
||||
# 则不应视为 typedef,应返回 None 让调用方走 struct 创建路径。
|
||||
# 解决时序问题:_parse_llvm_declare 从 stub.ll 解析时 dict 可能尚未注册到 Gen.structs,
|
||||
# 但 SymbolTable 在 .pyi 解析阶段已就绪,可通过 is_struct 检查区分 class 和 typedef。
|
||||
_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:
|
||||
if name in self.structs:
|
||||
return None # 已注册为 struct,不视为 typedef
|
||||
if self.SymbolTable is not None:
|
||||
try:
|
||||
if self.SymbolTable.is_struct(name):
|
||||
return None # SymbolTable 中标记为 struct,不视为 typedef
|
||||
except Exception:
|
||||
pass
|
||||
return 0 # 标记为 typedef,但位宽为 0(非整数)
|
||||
|
||||
return None
|
||||
|
||||
@@ -248,7 +248,15 @@ class StructGenMixin:
|
||||
if is_packed:
|
||||
self.structs[ClassName].packed = True
|
||||
continue
|
||||
mangled_name: str = self._mangle_name(ClassName)
|
||||
# 修复跨模块类型定义冲突:如果类是从其他模块导入的(已在 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
|
||||
|
||||
@@ -361,7 +369,18 @@ class StructGenMixin:
|
||||
_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)
|
||||
if len(existing_st.elements) >= _expected_count_pre and _vtable_first_ok:
|
||||
# 检测 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
|
||||
@@ -438,7 +457,12 @@ class StructGenMixin:
|
||||
# 由 _TryLoadStructFromStub 设置完整 body。
|
||||
member_types = []
|
||||
else:
|
||||
member_types = [ir.IntType(8)]
|
||||
# 无 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]
|
||||
@@ -454,10 +478,26 @@ class StructGenMixin:
|
||||
import_handler: Any = self._import_handler_ref
|
||||
if import_handler is not None and ClassName not in self._classes_in_progress:
|
||||
try:
|
||||
import_handler._TryLoadStructFromStub(ClassName, self)
|
||||
# 传入 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,
|
||||
@@ -485,18 +525,20 @@ class StructGenMixin:
|
||||
# _shared_class_vtable 和 _shared_cross_module_vtable,导致 class_vtable 与
|
||||
# _cross_module_vtable_classes 内容相同,无法用以区分本模块类与跨模块类。
|
||||
# _generate_structs 会为所有 class_methods 的类创建空 struct type,导致 self.structs
|
||||
# 也包含所有类。唯一可靠的过滤条件是 self.functions:_EmitClassLlvm 在本函数之前
|
||||
# 调用(LlvmGenerator.py L178-182),本模块定义的类方法已加入 self.functions;
|
||||
# import 声明的跨模块类方法也在 self.functions 中。若 self.functions 中没有任何
|
||||
# 以 "{ClassName}." 开头的键,说明本模块既未定义也未导入该类的方法,虚表会保持
|
||||
# 全 null,虚表分派时调用 null 指针引发段错误。此时应跳过虚表创建,让链接器
|
||||
# 从定义该类的模块解析虚表符号。
|
||||
# 也包含所有类。过滤条件是 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 in self.functions:
|
||||
for func_name, func_obj in self.functions.items():
|
||||
if func_name.startswith(prefix):
|
||||
has_local_method = True
|
||||
break
|
||||
# 跳过跨模块的 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))
|
||||
|
||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import types
|
||||
from typing import Any, ClassVar, Optional, TypeVar, Generic, TypeAlias
|
||||
from typing import Any, ClassVar, Optional, TypeVar, Generic, TypeAlias, Callable
|
||||
|
||||
from lib.constants.config import mode as _ConfigMode
|
||||
from lib.core.VLogger import get_logger as _vlog
|
||||
|
||||
Reference in New Issue
Block a user